##// END OF EJS Templates
Use common function for generation of grid data...
marcink -
r3154:0226b6d6 beta
parent child Browse files
Show More
@@ -1,628 +1,626 b''
1 1 """
2 2 Routes configuration
3 3
4 4 The more specific and detailed routes should be defined first so they
5 5 may take precedent over the more generic routes. For more information
6 6 refer to the routes manual at http://routes.groovie.org/docs/
7 7 """
8 8 from __future__ import with_statement
9 9 from routes import Mapper
10 10
11 11 # prefix for non repository related links needs to be prefixed with `/`
12 12 ADMIN_PREFIX = '/_admin'
13 13
14 14
15 15 def make_map(config):
16 16 """Create, configure and return the routes Mapper"""
17 17 rmap = Mapper(directory=config['pylons.paths']['controllers'],
18 18 always_scan=config['debug'])
19 19 rmap.minimization = False
20 20 rmap.explicit = False
21 21
22 22 from rhodecode.lib.utils import is_valid_repo
23 23 from rhodecode.lib.utils import is_valid_repos_group
24 24
25 25 def check_repo(environ, match_dict):
26 26 """
27 27 check for valid repository for proper 404 handling
28 28
29 29 :param environ:
30 30 :param match_dict:
31 31 """
32 32 from rhodecode.model.db import Repository
33 33 repo_name = match_dict.get('repo_name')
34 34
35 35 if match_dict.get('f_path'):
36 36 #fix for multiple initial slashes that causes errors
37 37 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
38 38
39 39 try:
40 40 by_id = repo_name.split('_')
41 41 if len(by_id) == 2 and by_id[1].isdigit() and by_id[0] == '':
42 42 repo_name = Repository.get(by_id[1]).repo_name
43 43 match_dict['repo_name'] = repo_name
44 44 except:
45 45 pass
46 46
47 47 return is_valid_repo(repo_name, config['base_path'])
48 48
49 49 def check_group(environ, match_dict):
50 50 """
51 51 check for valid repositories group for proper 404 handling
52 52
53 53 :param environ:
54 54 :param match_dict:
55 55 """
56 56 repos_group_name = match_dict.get('group_name')
57 57
58 58 return is_valid_repos_group(repos_group_name, config['base_path'])
59 59
60 60 def check_int(environ, match_dict):
61 61 return match_dict.get('id').isdigit()
62 62
63 63 # The ErrorController route (handles 404/500 error pages); it should
64 64 # likely stay at the top, ensuring it can always be resolved
65 65 rmap.connect('/error/{action}', controller='error')
66 66 rmap.connect('/error/{action}/{id}', controller='error')
67 67
68 68 #==========================================================================
69 69 # CUSTOM ROUTES HERE
70 70 #==========================================================================
71 71
72 72 #MAIN PAGE
73 73 rmap.connect('home', '/', controller='home', action='index')
74 74 rmap.connect('repo_switcher', '/repos', controller='home',
75 75 action='repo_switcher')
76 76 rmap.connect('branch_tag_switcher', '/branches-tags/{repo_name:.*?}',
77 77 controller='home', action='branch_tag_switcher')
78 78 rmap.connect('bugtracker',
79 79 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
80 80 _static=True)
81 81 rmap.connect('rst_help',
82 82 "http://docutils.sourceforge.net/docs/user/rst/quickref.html",
83 83 _static=True)
84 84 rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
85 85
86 86 #ADMIN REPOSITORY REST ROUTES
87 87 with rmap.submapper(path_prefix=ADMIN_PREFIX,
88 88 controller='admin/repos') as m:
89 89 m.connect("repos", "/repos",
90 90 action="create", conditions=dict(method=["POST"]))
91 91 m.connect("repos", "/repos",
92 92 action="index", conditions=dict(method=["GET"]))
93 93 m.connect("formatted_repos", "/repos.{format}",
94 94 action="index",
95 95 conditions=dict(method=["GET"]))
96 96 m.connect("new_repo", "/repos/new",
97 97 action="new", conditions=dict(method=["GET"]))
98 98 m.connect("formatted_new_repo", "/repos/new.{format}",
99 99 action="new", conditions=dict(method=["GET"]))
100 100 m.connect("/repos/{repo_name:.*?}",
101 101 action="update", conditions=dict(method=["PUT"],
102 102 function=check_repo))
103 103 m.connect("/repos/{repo_name:.*?}",
104 104 action="delete", conditions=dict(method=["DELETE"],
105 105 function=check_repo))
106 106 m.connect("edit_repo", "/repos/{repo_name:.*?}/edit",
107 107 action="edit", conditions=dict(method=["GET"],
108 108 function=check_repo))
109 109 m.connect("formatted_edit_repo", "/repos/{repo_name:.*?}.{format}/edit",
110 110 action="edit", conditions=dict(method=["GET"],
111 111 function=check_repo))
112 112 m.connect("repo", "/repos/{repo_name:.*?}",
113 113 action="show", conditions=dict(method=["GET"],
114 114 function=check_repo))
115 115 m.connect("formatted_repo", "/repos/{repo_name:.*?}.{format}",
116 116 action="show", conditions=dict(method=["GET"],
117 117 function=check_repo))
118 118 #ajax delete repo perm user
119 119 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*?}",
120 120 action="delete_perm_user",
121 121 conditions=dict(method=["DELETE"], function=check_repo))
122 122
123 123 #ajax delete repo perm users_group
124 124 m.connect('delete_repo_users_group',
125 125 "/repos_delete_users_group/{repo_name:.*?}",
126 126 action="delete_perm_users_group",
127 127 conditions=dict(method=["DELETE"], function=check_repo))
128 128
129 129 #settings actions
130 130 m.connect('repo_stats', "/repos_stats/{repo_name:.*?}",
131 131 action="repo_stats", conditions=dict(method=["DELETE"],
132 132 function=check_repo))
133 133 m.connect('repo_cache', "/repos_cache/{repo_name:.*?}",
134 134 action="repo_cache", conditions=dict(method=["DELETE"],
135 135 function=check_repo))
136 136 m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*?}",
137 137 action="repo_public_journal", conditions=dict(method=["PUT"],
138 138 function=check_repo))
139 139 m.connect('repo_pull', "/repo_pull/{repo_name:.*?}",
140 140 action="repo_pull", conditions=dict(method=["PUT"],
141 141 function=check_repo))
142 142 m.connect('repo_as_fork', "/repo_as_fork/{repo_name:.*?}",
143 143 action="repo_as_fork", conditions=dict(method=["PUT"],
144 144 function=check_repo))
145 145 m.connect('repo_locking', "/repo_locking/{repo_name:.*?}",
146 146 action="repo_locking", conditions=dict(method=["PUT"],
147 147 function=check_repo))
148 148
149 149 with rmap.submapper(path_prefix=ADMIN_PREFIX,
150 150 controller='admin/repos_groups') as m:
151 151 m.connect("repos_groups", "/repos_groups",
152 152 action="create", conditions=dict(method=["POST"]))
153 153 m.connect("repos_groups", "/repos_groups",
154 154 action="index", conditions=dict(method=["GET"]))
155 155 m.connect("formatted_repos_groups", "/repos_groups.{format}",
156 156 action="index", conditions=dict(method=["GET"]))
157 157 m.connect("new_repos_group", "/repos_groups/new",
158 158 action="new", conditions=dict(method=["GET"]))
159 159 m.connect("formatted_new_repos_group", "/repos_groups/new.{format}",
160 160 action="new", conditions=dict(method=["GET"]))
161 161 m.connect("update_repos_group", "/repos_groups/{id}",
162 162 action="update", conditions=dict(method=["PUT"],
163 163 function=check_int))
164 164 m.connect("delete_repos_group", "/repos_groups/{id}",
165 165 action="delete", conditions=dict(method=["DELETE"],
166 166 function=check_int))
167 167 m.connect("edit_repos_group", "/repos_groups/{id:.*?}/edit",
168 168 action="edit", conditions=dict(method=["GET"],))
169 169 m.connect("formatted_edit_repos_group",
170 170 "/repos_groups/{id}.{format}/edit",
171 171 action="edit", conditions=dict(method=["GET"],
172 172 function=check_int))
173 173 m.connect("repos_group", "/repos_groups/{id}",
174 174 action="show", conditions=dict(method=["GET"],
175 175 function=check_int))
176 176 m.connect("formatted_repos_group", "/repos_groups/{id}.{format}",
177 177 action="show", conditions=dict(method=["GET"],
178 178 function=check_int))
179 179 # ajax delete repos group perm user
180 180 m.connect('delete_repos_group_user_perm',
181 181 "/delete_repos_group_user_perm/{group_name:.*}",
182 182 action="delete_repos_group_user_perm",
183 183 conditions=dict(method=["DELETE"], function=check_group))
184 184
185 185 # ajax delete repos group perm users_group
186 186 m.connect('delete_repos_group_users_group_perm',
187 187 "/delete_repos_group_users_group_perm/{group_name:.*}",
188 188 action="delete_repos_group_users_group_perm",
189 189 conditions=dict(method=["DELETE"], function=check_group))
190 190
191 191 #ADMIN USER REST ROUTES
192 192 with rmap.submapper(path_prefix=ADMIN_PREFIX,
193 193 controller='admin/users') as m:
194 194 m.connect("users", "/users",
195 195 action="create", conditions=dict(method=["POST"]))
196 196 m.connect("users", "/users",
197 197 action="index", conditions=dict(method=["GET"]))
198 198 m.connect("formatted_users", "/users.{format}",
199 199 action="index", conditions=dict(method=["GET"]))
200 200 m.connect("new_user", "/users/new",
201 201 action="new", conditions=dict(method=["GET"]))
202 202 m.connect("formatted_new_user", "/users/new.{format}",
203 203 action="new", conditions=dict(method=["GET"]))
204 204 m.connect("update_user", "/users/{id}",
205 205 action="update", conditions=dict(method=["PUT"]))
206 206 m.connect("delete_user", "/users/{id}",
207 207 action="delete", conditions=dict(method=["DELETE"]))
208 208 m.connect("edit_user", "/users/{id}/edit",
209 209 action="edit", conditions=dict(method=["GET"]))
210 210 m.connect("formatted_edit_user",
211 211 "/users/{id}.{format}/edit",
212 212 action="edit", conditions=dict(method=["GET"]))
213 213 m.connect("user", "/users/{id}",
214 214 action="show", conditions=dict(method=["GET"]))
215 215 m.connect("formatted_user", "/users/{id}.{format}",
216 216 action="show", conditions=dict(method=["GET"]))
217 217
218 218 #EXTRAS USER ROUTES
219 219 m.connect("user_perm", "/users_perm/{id}",
220 220 action="update_perm", conditions=dict(method=["PUT"]))
221 221 m.connect("user_emails", "/users_emails/{id}",
222 222 action="add_email", conditions=dict(method=["PUT"]))
223 223 m.connect("user_emails_delete", "/users_emails/{id}",
224 224 action="delete_email", conditions=dict(method=["DELETE"]))
225 225 m.connect("user_ips", "/users_ips/{id}",
226 226 action="add_ip", conditions=dict(method=["PUT"]))
227 227 m.connect("user_ips_delete", "/users_ips/{id}",
228 228 action="delete_ip", conditions=dict(method=["DELETE"]))
229 229
230 230 #ADMIN USERS GROUPS REST ROUTES
231 231 with rmap.submapper(path_prefix=ADMIN_PREFIX,
232 232 controller='admin/users_groups') as m:
233 233 m.connect("users_groups", "/users_groups",
234 234 action="create", conditions=dict(method=["POST"]))
235 235 m.connect("users_groups", "/users_groups",
236 236 action="index", conditions=dict(method=["GET"]))
237 237 m.connect("formatted_users_groups", "/users_groups.{format}",
238 238 action="index", conditions=dict(method=["GET"]))
239 239 m.connect("new_users_group", "/users_groups/new",
240 240 action="new", conditions=dict(method=["GET"]))
241 241 m.connect("formatted_new_users_group", "/users_groups/new.{format}",
242 242 action="new", conditions=dict(method=["GET"]))
243 243 m.connect("update_users_group", "/users_groups/{id}",
244 244 action="update", conditions=dict(method=["PUT"]))
245 245 m.connect("delete_users_group", "/users_groups/{id}",
246 246 action="delete", conditions=dict(method=["DELETE"]))
247 247 m.connect("edit_users_group", "/users_groups/{id}/edit",
248 248 action="edit", conditions=dict(method=["GET"]))
249 249 m.connect("formatted_edit_users_group",
250 250 "/users_groups/{id}.{format}/edit",
251 251 action="edit", conditions=dict(method=["GET"]))
252 252 m.connect("users_group", "/users_groups/{id}",
253 253 action="show", conditions=dict(method=["GET"]))
254 254 m.connect("formatted_users_group", "/users_groups/{id}.{format}",
255 255 action="show", conditions=dict(method=["GET"]))
256 256
257 257 #EXTRAS USER ROUTES
258 258 m.connect("users_group_perm", "/users_groups_perm/{id}",
259 259 action="update_perm", conditions=dict(method=["PUT"]))
260 260
261 261 #ADMIN GROUP REST ROUTES
262 262 rmap.resource('group', 'groups',
263 263 controller='admin/groups', path_prefix=ADMIN_PREFIX)
264 264
265 265 #ADMIN PERMISSIONS REST ROUTES
266 266 rmap.resource('permission', 'permissions',
267 267 controller='admin/permissions', path_prefix=ADMIN_PREFIX)
268 268
269 269 #ADMIN DEFAULTS REST ROUTES
270 270 rmap.resource('default', 'defaults',
271 271 controller='admin/defaults', path_prefix=ADMIN_PREFIX)
272 272
273 273 ##ADMIN LDAP SETTINGS
274 274 rmap.connect('ldap_settings', '%s/ldap' % ADMIN_PREFIX,
275 275 controller='admin/ldap_settings', action='ldap_settings',
276 276 conditions=dict(method=["POST"]))
277 277
278 278 rmap.connect('ldap_home', '%s/ldap' % ADMIN_PREFIX,
279 279 controller='admin/ldap_settings')
280 280
281 281 #ADMIN SETTINGS REST ROUTES
282 282 with rmap.submapper(path_prefix=ADMIN_PREFIX,
283 283 controller='admin/settings') as m:
284 284 m.connect("admin_settings", "/settings",
285 285 action="create", conditions=dict(method=["POST"]))
286 286 m.connect("admin_settings", "/settings",
287 287 action="index", conditions=dict(method=["GET"]))
288 288 m.connect("formatted_admin_settings", "/settings.{format}",
289 289 action="index", conditions=dict(method=["GET"]))
290 290 m.connect("admin_new_setting", "/settings/new",
291 291 action="new", conditions=dict(method=["GET"]))
292 292 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
293 293 action="new", conditions=dict(method=["GET"]))
294 294 m.connect("/settings/{setting_id}",
295 295 action="update", conditions=dict(method=["PUT"]))
296 296 m.connect("/settings/{setting_id}",
297 297 action="delete", conditions=dict(method=["DELETE"]))
298 298 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
299 299 action="edit", conditions=dict(method=["GET"]))
300 300 m.connect("formatted_admin_edit_setting",
301 301 "/settings/{setting_id}.{format}/edit",
302 302 action="edit", conditions=dict(method=["GET"]))
303 303 m.connect("admin_setting", "/settings/{setting_id}",
304 304 action="show", conditions=dict(method=["GET"]))
305 305 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
306 306 action="show", conditions=dict(method=["GET"]))
307 307 m.connect("admin_settings_my_account", "/my_account",
308 308 action="my_account", conditions=dict(method=["GET"]))
309 309 m.connect("admin_settings_my_account_update", "/my_account_update",
310 310 action="my_account_update", conditions=dict(method=["PUT"]))
311 311 m.connect("admin_settings_create_repository", "/create_repository",
312 312 action="create_repository", conditions=dict(method=["GET"]))
313 313 m.connect("admin_settings_my_repos", "/my_account/repos",
314 314 action="my_account_my_repos", conditions=dict(method=["GET"]))
315 315 m.connect("admin_settings_my_pullrequests", "/my_account/pull_requests",
316 316 action="my_account_my_pullrequests", conditions=dict(method=["GET"]))
317 317
318 318 #NOTIFICATION REST ROUTES
319 319 with rmap.submapper(path_prefix=ADMIN_PREFIX,
320 320 controller='admin/notifications') as m:
321 321 m.connect("notifications", "/notifications",
322 322 action="create", conditions=dict(method=["POST"]))
323 323 m.connect("notifications", "/notifications",
324 324 action="index", conditions=dict(method=["GET"]))
325 325 m.connect("notifications_mark_all_read", "/notifications/mark_all_read",
326 326 action="mark_all_read", conditions=dict(method=["GET"]))
327 327 m.connect("formatted_notifications", "/notifications.{format}",
328 328 action="index", conditions=dict(method=["GET"]))
329 329 m.connect("new_notification", "/notifications/new",
330 330 action="new", conditions=dict(method=["GET"]))
331 331 m.connect("formatted_new_notification", "/notifications/new.{format}",
332 332 action="new", conditions=dict(method=["GET"]))
333 333 m.connect("/notification/{notification_id}",
334 334 action="update", conditions=dict(method=["PUT"]))
335 335 m.connect("/notification/{notification_id}",
336 336 action="delete", conditions=dict(method=["DELETE"]))
337 337 m.connect("edit_notification", "/notification/{notification_id}/edit",
338 338 action="edit", conditions=dict(method=["GET"]))
339 339 m.connect("formatted_edit_notification",
340 340 "/notification/{notification_id}.{format}/edit",
341 341 action="edit", conditions=dict(method=["GET"]))
342 342 m.connect("notification", "/notification/{notification_id}",
343 343 action="show", conditions=dict(method=["GET"]))
344 344 m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
345 345 action="show", conditions=dict(method=["GET"]))
346 346
347 347 #ADMIN MAIN PAGES
348 348 with rmap.submapper(path_prefix=ADMIN_PREFIX,
349 349 controller='admin/admin') as m:
350 350 m.connect('admin_home', '', action='index')
351 351 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
352 352 action='add_repo')
353 353
354 354 #==========================================================================
355 355 # API V2
356 356 #==========================================================================
357 357 with rmap.submapper(path_prefix=ADMIN_PREFIX,
358 358 controller='api/api') as m:
359 359 m.connect('api', '/api')
360 360
361 361 #USER JOURNAL
362 rmap.connect('journal_my_repos', '%s/journal_my_repos' % ADMIN_PREFIX,
363 controller='journal', action='index_my_repos')
364 362 rmap.connect('journal', '%s/journal' % ADMIN_PREFIX,
365 363 controller='journal', action='index')
366 364 rmap.connect('journal_rss', '%s/journal/rss' % ADMIN_PREFIX,
367 365 controller='journal', action='journal_rss')
368 366 rmap.connect('journal_atom', '%s/journal/atom' % ADMIN_PREFIX,
369 367 controller='journal', action='journal_atom')
370 368
371 369 rmap.connect('public_journal', '%s/public_journal' % ADMIN_PREFIX,
372 370 controller='journal', action="public_journal")
373 371
374 372 rmap.connect('public_journal_rss', '%s/public_journal/rss' % ADMIN_PREFIX,
375 373 controller='journal', action="public_journal_rss")
376 374
377 375 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % ADMIN_PREFIX,
378 376 controller='journal', action="public_journal_rss")
379 377
380 378 rmap.connect('public_journal_atom',
381 379 '%s/public_journal/atom' % ADMIN_PREFIX, controller='journal',
382 380 action="public_journal_atom")
383 381
384 382 rmap.connect('public_journal_atom_old',
385 383 '%s/public_journal_atom' % ADMIN_PREFIX, controller='journal',
386 384 action="public_journal_atom")
387 385
388 386 rmap.connect('toggle_following', '%s/toggle_following' % ADMIN_PREFIX,
389 387 controller='journal', action='toggle_following',
390 388 conditions=dict(method=["POST"]))
391 389
392 390 #SEARCH
393 391 rmap.connect('search', '%s/search' % ADMIN_PREFIX, controller='search',)
394 392 rmap.connect('search_repo', '%s/search/{search_repo:.*}' % ADMIN_PREFIX,
395 393 controller='search')
396 394
397 395 #LOGIN/LOGOUT/REGISTER/SIGN IN
398 396 rmap.connect('login_home', '%s/login' % ADMIN_PREFIX, controller='login')
399 397 rmap.connect('logout_home', '%s/logout' % ADMIN_PREFIX, controller='login',
400 398 action='logout')
401 399
402 400 rmap.connect('register', '%s/register' % ADMIN_PREFIX, controller='login',
403 401 action='register')
404 402
405 403 rmap.connect('reset_password', '%s/password_reset' % ADMIN_PREFIX,
406 404 controller='login', action='password_reset')
407 405
408 406 rmap.connect('reset_password_confirmation',
409 407 '%s/password_reset_confirmation' % ADMIN_PREFIX,
410 408 controller='login', action='password_reset_confirmation')
411 409
412 410 #FEEDS
413 411 rmap.connect('rss_feed_home', '/{repo_name:.*?}/feed/rss',
414 412 controller='feed', action='rss',
415 413 conditions=dict(function=check_repo))
416 414
417 415 rmap.connect('atom_feed_home', '/{repo_name:.*?}/feed/atom',
418 416 controller='feed', action='atom',
419 417 conditions=dict(function=check_repo))
420 418
421 419 #==========================================================================
422 420 # REPOSITORY ROUTES
423 421 #==========================================================================
424 422 rmap.connect('summary_home', '/{repo_name:.*?}',
425 423 controller='summary',
426 424 conditions=dict(function=check_repo))
427 425
428 426 rmap.connect('repos_group_home', '/{group_name:.*}',
429 427 controller='admin/repos_groups', action="show_by_name",
430 428 conditions=dict(function=check_group))
431 429
432 430 rmap.connect('changeset_home', '/{repo_name:.*?}/changeset/{revision}',
433 431 controller='changeset', revision='tip',
434 432 conditions=dict(function=check_repo))
435 433
436 434 #still working url for backward compat.
437 435 rmap.connect('raw_changeset_home_depraced',
438 436 '/{repo_name:.*?}/raw-changeset/{revision}',
439 437 controller='changeset', action='changeset_raw',
440 438 revision='tip', conditions=dict(function=check_repo))
441 439
442 440 ## new URLs
443 441 rmap.connect('changeset_raw_home',
444 442 '/{repo_name:.*?}/changeset-diff/{revision}',
445 443 controller='changeset', action='changeset_raw',
446 444 revision='tip', conditions=dict(function=check_repo))
447 445
448 446 rmap.connect('changeset_patch_home',
449 447 '/{repo_name:.*?}/changeset-patch/{revision}',
450 448 controller='changeset', action='changeset_patch',
451 449 revision='tip', conditions=dict(function=check_repo))
452 450
453 451 rmap.connect('changeset_download_home',
454 452 '/{repo_name:.*?}/changeset-download/{revision}',
455 453 controller='changeset', action='changeset_download',
456 454 revision='tip', conditions=dict(function=check_repo))
457 455
458 456 rmap.connect('changeset_comment',
459 457 '/{repo_name:.*?}/changeset/{revision}/comment',
460 458 controller='changeset', revision='tip', action='comment',
461 459 conditions=dict(function=check_repo))
462 460
463 461 rmap.connect('changeset_comment_delete',
464 462 '/{repo_name:.*?}/changeset/comment/{comment_id}/delete',
465 463 controller='changeset', action='delete_comment',
466 464 conditions=dict(function=check_repo, method=["DELETE"]))
467 465
468 466 rmap.connect('changeset_info', '/changeset_info/{repo_name:.*?}/{revision}',
469 467 controller='changeset', action='changeset_info')
470 468
471 469 rmap.connect('compare_url',
472 470 '/{repo_name:.*?}/compare/{org_ref_type}@{org_ref:.*?}...{other_ref_type}@{other_ref:.*?}',
473 471 controller='compare', action='index',
474 472 conditions=dict(function=check_repo),
475 473 requirements=dict(
476 474 org_ref_type='(branch|book|tag|rev|org_ref_type)',
477 475 other_ref_type='(branch|book|tag|rev|other_ref_type)')
478 476 )
479 477
480 478 rmap.connect('pullrequest_home',
481 479 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
482 480 action='index', conditions=dict(function=check_repo,
483 481 method=["GET"]))
484 482
485 483 rmap.connect('pullrequest',
486 484 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
487 485 action='create', conditions=dict(function=check_repo,
488 486 method=["POST"]))
489 487
490 488 rmap.connect('pullrequest_show',
491 489 '/{repo_name:.*?}/pull-request/{pull_request_id}',
492 490 controller='pullrequests',
493 491 action='show', conditions=dict(function=check_repo,
494 492 method=["GET"]))
495 493 rmap.connect('pullrequest_update',
496 494 '/{repo_name:.*?}/pull-request/{pull_request_id}',
497 495 controller='pullrequests',
498 496 action='update', conditions=dict(function=check_repo,
499 497 method=["PUT"]))
500 498 rmap.connect('pullrequest_delete',
501 499 '/{repo_name:.*?}/pull-request/{pull_request_id}',
502 500 controller='pullrequests',
503 501 action='delete', conditions=dict(function=check_repo,
504 502 method=["DELETE"]))
505 503
506 504 rmap.connect('pullrequest_show_all',
507 505 '/{repo_name:.*?}/pull-request',
508 506 controller='pullrequests',
509 507 action='show_all', conditions=dict(function=check_repo,
510 508 method=["GET"]))
511 509
512 510 rmap.connect('pullrequest_comment',
513 511 '/{repo_name:.*?}/pull-request-comment/{pull_request_id}',
514 512 controller='pullrequests',
515 513 action='comment', conditions=dict(function=check_repo,
516 514 method=["POST"]))
517 515
518 516 rmap.connect('pullrequest_comment_delete',
519 517 '/{repo_name:.*?}/pull-request-comment/{comment_id}/delete',
520 518 controller='pullrequests', action='delete_comment',
521 519 conditions=dict(function=check_repo, method=["DELETE"]))
522 520
523 521 rmap.connect('summary_home', '/{repo_name:.*?}/summary',
524 522 controller='summary', conditions=dict(function=check_repo))
525 523
526 524 rmap.connect('shortlog_home', '/{repo_name:.*?}/shortlog',
527 525 controller='shortlog', conditions=dict(function=check_repo))
528 526
529 527 rmap.connect('shortlog_file_home', '/{repo_name:.*?}/shortlog/{revision}/{f_path:.*}',
530 528 controller='shortlog', f_path=None,
531 529 conditions=dict(function=check_repo))
532 530
533 531 rmap.connect('branches_home', '/{repo_name:.*?}/branches',
534 532 controller='branches', conditions=dict(function=check_repo))
535 533
536 534 rmap.connect('tags_home', '/{repo_name:.*?}/tags',
537 535 controller='tags', conditions=dict(function=check_repo))
538 536
539 537 rmap.connect('bookmarks_home', '/{repo_name:.*?}/bookmarks',
540 538 controller='bookmarks', conditions=dict(function=check_repo))
541 539
542 540 rmap.connect('changelog_home', '/{repo_name:.*?}/changelog',
543 541 controller='changelog', conditions=dict(function=check_repo))
544 542
545 543 rmap.connect('changelog_details', '/{repo_name:.*?}/changelog_details/{cs}',
546 544 controller='changelog', action='changelog_details',
547 545 conditions=dict(function=check_repo))
548 546
549 547 rmap.connect('files_home', '/{repo_name:.*?}/files/{revision}/{f_path:.*}',
550 548 controller='files', revision='tip', f_path='',
551 549 conditions=dict(function=check_repo))
552 550
553 551 rmap.connect('files_history_home',
554 552 '/{repo_name:.*?}/history/{revision}/{f_path:.*}',
555 553 controller='files', action='history', revision='tip', f_path='',
556 554 conditions=dict(function=check_repo))
557 555
558 556 rmap.connect('files_diff_home', '/{repo_name:.*?}/diff/{f_path:.*}',
559 557 controller='files', action='diff', revision='tip', f_path='',
560 558 conditions=dict(function=check_repo))
561 559
562 560 rmap.connect('files_rawfile_home',
563 561 '/{repo_name:.*?}/rawfile/{revision}/{f_path:.*}',
564 562 controller='files', action='rawfile', revision='tip',
565 563 f_path='', conditions=dict(function=check_repo))
566 564
567 565 rmap.connect('files_raw_home',
568 566 '/{repo_name:.*?}/raw/{revision}/{f_path:.*}',
569 567 controller='files', action='raw', revision='tip', f_path='',
570 568 conditions=dict(function=check_repo))
571 569
572 570 rmap.connect('files_annotate_home',
573 571 '/{repo_name:.*?}/annotate/{revision}/{f_path:.*}',
574 572 controller='files', action='index', revision='tip',
575 573 f_path='', annotate=True, conditions=dict(function=check_repo))
576 574
577 575 rmap.connect('files_edit_home',
578 576 '/{repo_name:.*?}/edit/{revision}/{f_path:.*}',
579 577 controller='files', action='edit', revision='tip',
580 578 f_path='', conditions=dict(function=check_repo))
581 579
582 580 rmap.connect('files_add_home',
583 581 '/{repo_name:.*?}/add/{revision}/{f_path:.*}',
584 582 controller='files', action='add', revision='tip',
585 583 f_path='', conditions=dict(function=check_repo))
586 584
587 585 rmap.connect('files_archive_home', '/{repo_name:.*?}/archive/{fname}',
588 586 controller='files', action='archivefile',
589 587 conditions=dict(function=check_repo))
590 588
591 589 rmap.connect('files_nodelist_home',
592 590 '/{repo_name:.*?}/nodelist/{revision}/{f_path:.*}',
593 591 controller='files', action='nodelist',
594 592 conditions=dict(function=check_repo))
595 593
596 594 rmap.connect('repo_settings_delete', '/{repo_name:.*?}/settings',
597 595 controller='settings', action="delete",
598 596 conditions=dict(method=["DELETE"], function=check_repo))
599 597
600 598 rmap.connect('repo_settings_update', '/{repo_name:.*?}/settings',
601 599 controller='settings', action="update",
602 600 conditions=dict(method=["PUT"], function=check_repo))
603 601
604 602 rmap.connect('repo_settings_home', '/{repo_name:.*?}/settings',
605 603 controller='settings', action='index',
606 604 conditions=dict(function=check_repo))
607 605
608 606 rmap.connect('toggle_locking', "/{repo_name:.*?}/locking_toggle",
609 607 controller='settings', action="toggle_locking",
610 608 conditions=dict(method=["GET"], function=check_repo))
611 609
612 610 rmap.connect('repo_fork_create_home', '/{repo_name:.*?}/fork',
613 611 controller='forks', action='fork_create',
614 612 conditions=dict(function=check_repo, method=["POST"]))
615 613
616 614 rmap.connect('repo_fork_home', '/{repo_name:.*?}/fork',
617 615 controller='forks', action='fork',
618 616 conditions=dict(function=check_repo))
619 617
620 618 rmap.connect('repo_forks_home', '/{repo_name:.*?}/forks',
621 619 controller='forks', action='forks',
622 620 conditions=dict(function=check_repo))
623 621
624 622 rmap.connect('repo_followers_home', '/{repo_name:.*?}/followers',
625 623 controller='followers', action='followers',
626 624 conditions=dict(function=check_repo))
627 625
628 626 return rmap
@@ -1,510 +1,480 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.repos
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Repositories controller for RhodeCode
7 7
8 8 :created_on: Apr 7, 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 29 from formencode import htmlfill
30 30
31 31 from webob.exc import HTTPInternalServerError
32 32 from pylons import request, session, tmpl_context as c, url
33 33 from pylons.controllers.util import redirect
34 34 from pylons.i18n.translation import _
35 35 from sqlalchemy.exc import IntegrityError
36 36
37 37 import rhodecode
38 38 from rhodecode.lib import helpers as h
39 39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 40 HasPermissionAnyDecorator, HasRepoPermissionAllDecorator
41 41 from rhodecode.lib.base import BaseController, render
42 42 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
43 43 from rhodecode.lib.helpers import get_token
44 44 from rhodecode.model.meta import Session
45 45 from rhodecode.model.db import User, Repository, UserFollowing, RepoGroup,\
46 46 RhodeCodeSetting
47 47 from rhodecode.model.forms import RepoForm
48 48 from rhodecode.model.scm import ScmModel
49 49 from rhodecode.model.repo import RepoModel
50 50 from rhodecode.lib.compat import json
51 51 from sqlalchemy.sql.expression import func
52 52
53 53 log = logging.getLogger(__name__)
54 54
55 55
56 56 class ReposController(BaseController):
57 57 """
58 58 REST Controller styled on the Atom Publishing Protocol"""
59 59 # To properly map this controller, ensure your config/routing.py
60 60 # file has a resource setup:
61 61 # map.resource('repo', 'repos')
62 62
63 63 @LoginRequired()
64 64 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
65 65 def __before__(self):
66 66 c.admin_user = session.get('admin_user')
67 67 c.admin_username = session.get('admin_username')
68 68 super(ReposController, self).__before__()
69 69
70 70 def __load_defaults(self):
71 71 c.repo_groups = RepoGroup.groups_choices(check_perms=True)
72 72 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
73 73
74 74 repo_model = RepoModel()
75 75 c.users_array = repo_model.get_users_js()
76 76 c.users_groups_array = repo_model.get_users_groups_js()
77 77 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
78 78 c.landing_revs_choices = choices
79 79
80 80 def __load_data(self, repo_name=None):
81 81 """
82 82 Load defaults settings for edit, and update
83 83
84 84 :param repo_name:
85 85 """
86 86 self.__load_defaults()
87 87
88 88 c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
89 89 repo = db_repo.scm_instance
90 90
91 91 if c.repo_info is None:
92 92 h.not_mapped_error(repo_name)
93 93 return redirect(url('repos'))
94 94
95 95 ##override defaults for exact repo info here git/hg etc
96 96 choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info)
97 97 c.landing_revs_choices = choices
98 98
99 99 c.default_user_id = User.get_by_username('default').user_id
100 100 c.in_public_journal = UserFollowing.query()\
101 101 .filter(UserFollowing.user_id == c.default_user_id)\
102 102 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
103 103
104 104 if c.repo_info.stats:
105 105 # this is on what revision we ended up so we add +1 for count
106 106 last_rev = c.repo_info.stats.stat_on_revision + 1
107 107 else:
108 108 last_rev = 0
109 109 c.stats_revision = last_rev
110 110
111 111 c.repo_last_rev = repo.count() if repo.revisions else 0
112 112
113 113 if last_rev == 0 or c.repo_last_rev == 0:
114 114 c.stats_percentage = 0
115 115 else:
116 116 c.stats_percentage = '%.2f' % ((float((last_rev)) /
117 117 c.repo_last_rev) * 100)
118 118
119 119 defaults = RepoModel()._get_defaults(repo_name)
120 120
121 121 c.repos_list = [('', _('--REMOVE FORK--'))]
122 122 c.repos_list += [(x.repo_id, x.repo_name) for x in
123 123 Repository.query().order_by(Repository.repo_name).all()
124 124 if x.repo_id != c.repo_info.repo_id]
125 125
126 126 defaults['id_fork_of'] = db_repo.fork.repo_id if db_repo.fork else ''
127 127 return defaults
128 128
129 129 @HasPermissionAllDecorator('hg.admin')
130 130 def index(self, format='html'):
131 131 """GET /repos: All items in the collection"""
132 132 # url('repos')
133 133
134 134 c.repos_list = Repository.query()\
135 135 .order_by(func.lower(Repository.repo_name))\
136 136 .all()
137 137
138 repos_data = []
139 total_records = len(c.repos_list)
140
141 _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
142 template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
143
144 quick_menu = lambda repo_name: (template.get_def("quick_menu")
145 .render(repo_name, _=_, h=h, c=c))
146 repo_lnk = lambda name, rtype, private, fork_of: (
147 template.get_def("repo_name")
148 .render(name, rtype, private, fork_of, short_name=False,
149 admin=True, _=_, h=h, c=c))
150
151 repo_actions = lambda repo_name: (template.get_def("repo_actions")
152 .render(repo_name, _=_, h=h, c=c))
153
154 for repo in c.repos_list:
155 repos_data.append({
156 "menu": quick_menu(repo.repo_name),
157 "raw_name": repo.repo_name.lower(),
158 "name": repo_lnk(repo.repo_name, repo.repo_type,
159 repo.private, repo.fork),
160 "desc": repo.description,
161 "owner": repo.user.username,
162 "action": repo_actions(repo.repo_name),
163 })
164
165 c.data = json.dumps({
166 "totalRecords": total_records,
167 "startIndex": 0,
168 "sort": "name",
169 "dir": "asc",
170 "records": repos_data
171 })
138 repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
139 admin=True)
140 #json used to render the grid
141 c.data = json.dumps(repos_data)
172 142
173 143 return render('admin/repos/repos.html')
174 144
175 145 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
176 146 def create(self):
177 147 """
178 148 POST /repos: Create a new item"""
179 149 # url('repos')
180 150
181 151 self.__load_defaults()
182 152 form_result = {}
183 153 try:
184 154 form_result = RepoForm(repo_groups=c.repo_groups_choices,
185 155 landing_revs=c.landing_revs_choices)()\
186 156 .to_python(dict(request.POST))
187 157 new_repo = RepoModel().create(form_result,
188 158 self.rhodecode_user.user_id)
189 159 if form_result['clone_uri']:
190 160 h.flash(_('created repository %s from %s') \
191 161 % (form_result['repo_name'], form_result['clone_uri']),
192 162 category='success')
193 163 else:
194 164 h.flash(_('created repository %s') % form_result['repo_name'],
195 165 category='success')
196 166
197 167 if request.POST.get('user_created'):
198 168 # created by regular non admin user
199 169 action_logger(self.rhodecode_user, 'user_created_repo',
200 170 form_result['repo_name_full'], self.ip_addr,
201 171 self.sa)
202 172 else:
203 173 action_logger(self.rhodecode_user, 'admin_created_repo',
204 174 form_result['repo_name_full'], self.ip_addr,
205 175 self.sa)
206 176 Session().commit()
207 177 except formencode.Invalid, errors:
208 178
209 179 c.new_repo = errors.value['repo_name']
210 180
211 181 if request.POST.get('user_created'):
212 182 r = render('admin/repos/repo_add_create_repository.html')
213 183 else:
214 184 r = render('admin/repos/repo_add.html')
215 185
216 186 return htmlfill.render(
217 187 r,
218 188 defaults=errors.value,
219 189 errors=errors.error_dict or {},
220 190 prefix_error=False,
221 191 encoding="UTF-8")
222 192
223 193 except Exception:
224 194 log.error(traceback.format_exc())
225 195 msg = _('error occurred during creation of repository %s') \
226 196 % form_result.get('repo_name')
227 197 h.flash(msg, category='error')
228 198 return redirect(url('repos'))
229 199 #redirect to our new repo !
230 200 return redirect(url('summary_home', repo_name=new_repo.repo_name))
231 201
232 202 @HasPermissionAllDecorator('hg.admin')
233 203 def new(self, format='html'):
234 204 """GET /repos/new: Form to create a new item"""
235 205 new_repo = request.GET.get('repo', '')
236 206 c.new_repo = repo_name_slug(new_repo)
237 207 self.__load_defaults()
238 208 ## apply the defaults from defaults page
239 209 defaults = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
240 210 return htmlfill.render(
241 211 render('admin/repos/repo_add.html'),
242 212 defaults=defaults,
243 213 errors={},
244 214 prefix_error=False,
245 215 encoding="UTF-8"
246 216 )
247 217
248 218 @HasPermissionAllDecorator('hg.admin')
249 219 def update(self, repo_name):
250 220 """
251 221 PUT /repos/repo_name: Update an existing item"""
252 222 # Forms posted to this method should contain a hidden field:
253 223 # <input type="hidden" name="_method" value="PUT" />
254 224 # Or using helpers:
255 225 # h.form(url('repo', repo_name=ID),
256 226 # method='put')
257 227 # url('repo', repo_name=ID)
258 228 self.__load_defaults()
259 229 repo_model = RepoModel()
260 230 changed_name = repo_name
261 231 #override the choices with extracted revisions !
262 232 choices, c.landing_revs = ScmModel().get_repo_landing_revs(repo_name)
263 233 c.landing_revs_choices = choices
264 234
265 235 _form = RepoForm(edit=True, old_data={'repo_name': repo_name},
266 236 repo_groups=c.repo_groups_choices,
267 237 landing_revs=c.landing_revs_choices)()
268 238 try:
269 239 form_result = _form.to_python(dict(request.POST))
270 240 repo = repo_model.update(repo_name, **form_result)
271 241 invalidate_cache('get_repo_cached_%s' % repo_name)
272 242 h.flash(_('Repository %s updated successfully') % repo_name,
273 243 category='success')
274 244 changed_name = repo.repo_name
275 245 action_logger(self.rhodecode_user, 'admin_updated_repo',
276 246 changed_name, self.ip_addr, self.sa)
277 247 Session().commit()
278 248 except formencode.Invalid, errors:
279 249 defaults = self.__load_data(repo_name)
280 250 defaults.update(errors.value)
281 251 return htmlfill.render(
282 252 render('admin/repos/repo_edit.html'),
283 253 defaults=defaults,
284 254 errors=errors.error_dict or {},
285 255 prefix_error=False,
286 256 encoding="UTF-8")
287 257
288 258 except Exception:
289 259 log.error(traceback.format_exc())
290 260 h.flash(_('error occurred during update of repository %s') \
291 261 % repo_name, category='error')
292 262 return redirect(url('edit_repo', repo_name=changed_name))
293 263
294 264 @HasPermissionAllDecorator('hg.admin')
295 265 def delete(self, repo_name):
296 266 """
297 267 DELETE /repos/repo_name: Delete an existing item"""
298 268 # Forms posted to this method should contain a hidden field:
299 269 # <input type="hidden" name="_method" value="DELETE" />
300 270 # Or using helpers:
301 271 # h.form(url('repo', repo_name=ID),
302 272 # method='delete')
303 273 # url('repo', repo_name=ID)
304 274
305 275 repo_model = RepoModel()
306 276 repo = repo_model.get_by_repo_name(repo_name)
307 277 if not repo:
308 278 h.not_mapped_error(repo_name)
309 279 return redirect(url('repos'))
310 280 try:
311 281 action_logger(self.rhodecode_user, 'admin_deleted_repo',
312 282 repo_name, self.ip_addr, self.sa)
313 283 repo_model.delete(repo)
314 284 invalidate_cache('get_repo_cached_%s' % repo_name)
315 285 h.flash(_('deleted repository %s') % repo_name, category='success')
316 286 Session().commit()
317 287 except IntegrityError, e:
318 288 if e.message.find('repositories_fork_id_fkey') != -1:
319 289 log.error(traceback.format_exc())
320 290 h.flash(_('Cannot delete %s it still contains attached '
321 291 'forks') % repo_name,
322 292 category='warning')
323 293 else:
324 294 log.error(traceback.format_exc())
325 295 h.flash(_('An error occurred during '
326 296 'deletion of %s') % repo_name,
327 297 category='error')
328 298
329 299 except Exception, e:
330 300 log.error(traceback.format_exc())
331 301 h.flash(_('An error occurred during deletion of %s') % repo_name,
332 302 category='error')
333 303
334 304 return redirect(url('repos'))
335 305
336 306 @HasRepoPermissionAllDecorator('repository.admin')
337 307 def delete_perm_user(self, repo_name):
338 308 """
339 309 DELETE an existing repository permission user
340 310
341 311 :param repo_name:
342 312 """
343 313 try:
344 314 RepoModel().revoke_user_permission(repo=repo_name,
345 315 user=request.POST['user_id'])
346 316 Session().commit()
347 317 except Exception:
348 318 log.error(traceback.format_exc())
349 319 h.flash(_('An error occurred during deletion of repository user'),
350 320 category='error')
351 321 raise HTTPInternalServerError()
352 322
353 323 @HasRepoPermissionAllDecorator('repository.admin')
354 324 def delete_perm_users_group(self, repo_name):
355 325 """
356 326 DELETE an existing repository permission users group
357 327
358 328 :param repo_name:
359 329 """
360 330
361 331 try:
362 332 RepoModel().revoke_users_group_permission(
363 333 repo=repo_name, group_name=request.POST['users_group_id']
364 334 )
365 335 Session().commit()
366 336 except Exception:
367 337 log.error(traceback.format_exc())
368 338 h.flash(_('An error occurred during deletion of repository'
369 339 ' users groups'),
370 340 category='error')
371 341 raise HTTPInternalServerError()
372 342
373 343 @HasPermissionAllDecorator('hg.admin')
374 344 def repo_stats(self, repo_name):
375 345 """
376 346 DELETE an existing repository statistics
377 347
378 348 :param repo_name:
379 349 """
380 350
381 351 try:
382 352 RepoModel().delete_stats(repo_name)
383 353 Session().commit()
384 354 except Exception, e:
385 355 log.error(traceback.format_exc())
386 356 h.flash(_('An error occurred during deletion of repository stats'),
387 357 category='error')
388 358 return redirect(url('edit_repo', repo_name=repo_name))
389 359
390 360 @HasPermissionAllDecorator('hg.admin')
391 361 def repo_cache(self, repo_name):
392 362 """
393 363 INVALIDATE existing repository cache
394 364
395 365 :param repo_name:
396 366 """
397 367
398 368 try:
399 369 ScmModel().mark_for_invalidation(repo_name)
400 370 Session().commit()
401 371 except Exception, e:
402 372 log.error(traceback.format_exc())
403 373 h.flash(_('An error occurred during cache invalidation'),
404 374 category='error')
405 375 return redirect(url('edit_repo', repo_name=repo_name))
406 376
407 377 @HasPermissionAllDecorator('hg.admin')
408 378 def repo_locking(self, repo_name):
409 379 """
410 380 Unlock repository when it is locked !
411 381
412 382 :param repo_name:
413 383 """
414 384
415 385 try:
416 386 repo = Repository.get_by_repo_name(repo_name)
417 387 if request.POST.get('set_lock'):
418 388 Repository.lock(repo, c.rhodecode_user.user_id)
419 389 elif request.POST.get('set_unlock'):
420 390 Repository.unlock(repo)
421 391 except Exception, e:
422 392 log.error(traceback.format_exc())
423 393 h.flash(_('An error occurred during unlocking'),
424 394 category='error')
425 395 return redirect(url('edit_repo', repo_name=repo_name))
426 396
427 397 @HasPermissionAllDecorator('hg.admin')
428 398 def repo_public_journal(self, repo_name):
429 399 """
430 400 Set's this repository to be visible in public journal,
431 401 in other words assing default user to follow this repo
432 402
433 403 :param repo_name:
434 404 """
435 405
436 406 cur_token = request.POST.get('auth_token')
437 407 token = get_token()
438 408 if cur_token == token:
439 409 try:
440 410 repo_id = Repository.get_by_repo_name(repo_name).repo_id
441 411 user_id = User.get_by_username('default').user_id
442 412 self.scm_model.toggle_following_repo(repo_id, user_id)
443 413 h.flash(_('Updated repository visibility in public journal'),
444 414 category='success')
445 415 Session().commit()
446 416 except:
447 417 h.flash(_('An error occurred during setting this'
448 418 ' repository in public journal'),
449 419 category='error')
450 420
451 421 else:
452 422 h.flash(_('Token mismatch'), category='error')
453 423 return redirect(url('edit_repo', repo_name=repo_name))
454 424
455 425 @HasPermissionAllDecorator('hg.admin')
456 426 def repo_pull(self, repo_name):
457 427 """
458 428 Runs task to update given repository with remote changes,
459 429 ie. make pull on remote location
460 430
461 431 :param repo_name:
462 432 """
463 433 try:
464 434 ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
465 435 h.flash(_('Pulled from remote location'), category='success')
466 436 except Exception, e:
467 437 h.flash(_('An error occurred during pull from remote location'),
468 438 category='error')
469 439
470 440 return redirect(url('edit_repo', repo_name=repo_name))
471 441
472 442 @HasPermissionAllDecorator('hg.admin')
473 443 def repo_as_fork(self, repo_name):
474 444 """
475 445 Mark given repository as a fork of another
476 446
477 447 :param repo_name:
478 448 """
479 449 try:
480 450 fork_id = request.POST.get('id_fork_of')
481 451 repo = ScmModel().mark_as_fork(repo_name, fork_id,
482 452 self.rhodecode_user.username)
483 453 fork = repo.fork.repo_name if repo.fork else _('Nothing')
484 454 Session().commit()
485 455 h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork),
486 456 category='success')
487 457 except Exception, e:
488 458 log.error(traceback.format_exc())
489 459 h.flash(_('An error occurred during this operation'),
490 460 category='error')
491 461
492 462 return redirect(url('edit_repo', repo_name=repo_name))
493 463
494 464 @HasPermissionAllDecorator('hg.admin')
495 465 def show(self, repo_name, format='html'):
496 466 """GET /repos/repo_name: Show a specific item"""
497 467 # url('repo', repo_name=ID)
498 468
499 469 @HasPermissionAllDecorator('hg.admin')
500 470 def edit(self, repo_name, format='html'):
501 471 """GET /repos/repo_name/edit: Form to edit an existing item"""
502 472 # url('edit_repo', repo_name=ID)
503 473 defaults = self.__load_data(repo_name)
504 474
505 475 return htmlfill.render(
506 476 render('admin/repos/repo_edit.html'),
507 477 defaults=defaults,
508 478 encoding="UTF-8",
509 479 force_defaults=False
510 480 )
@@ -1,366 +1,330 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.repos_groups
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Repositories groups controller for RhodeCode
7 7
8 8 :created_on: Mar 23, 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 29
30 30 from formencode import htmlfill
31 31
32 32 from pylons import request, tmpl_context as c, url
33 33 from pylons.controllers.util import redirect
34 34 from pylons.i18n.translation import _
35 35
36 36 from sqlalchemy.exc import IntegrityError
37 37
38 38 import rhodecode
39 39 from rhodecode.lib import helpers as h
40 40 from rhodecode.lib.ext_json import json
41 41 from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator,\
42 42 HasReposGroupPermissionAnyDecorator
43 43 from rhodecode.lib.base import BaseController, render
44 44 from rhodecode.model.db import RepoGroup, Repository
45 45 from rhodecode.model.repos_group import ReposGroupModel
46 46 from rhodecode.model.forms import ReposGroupForm
47 47 from rhodecode.model.meta import Session
48 48 from rhodecode.model.repo import RepoModel
49 49 from webob.exc import HTTPInternalServerError, HTTPNotFound
50 50 from rhodecode.lib.utils2 import str2bool
51 51 from sqlalchemy.sql.expression import func
52 52
53 53 log = logging.getLogger(__name__)
54 54
55 55
56 56 class ReposGroupsController(BaseController):
57 57 """REST Controller styled on the Atom Publishing Protocol"""
58 58 # To properly map this controller, ensure your config/routing.py
59 59 # file has a resource setup:
60 60 # map.resource('repos_group', 'repos_groups')
61 61
62 62 @LoginRequired()
63 63 def __before__(self):
64 64 super(ReposGroupsController, self).__before__()
65 65
66 66 def __load_defaults(self):
67 67 c.repo_groups = RepoGroup.groups_choices()
68 68 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
69 69
70 70 repo_model = RepoModel()
71 71 c.users_array = repo_model.get_users_js()
72 72 c.users_groups_array = repo_model.get_users_groups_js()
73 73
74 74 def __load_data(self, group_id):
75 75 """
76 76 Load defaults settings for edit, and update
77 77
78 78 :param group_id:
79 79 """
80 80 self.__load_defaults()
81 81 repo_group = RepoGroup.get_or_404(group_id)
82 82 data = repo_group.get_dict()
83 83 data['group_name'] = repo_group.name
84 84
85 85 # fill repository users
86 86 for p in repo_group.repo_group_to_perm:
87 87 data.update({'u_perm_%s' % p.user.username:
88 88 p.permission.permission_name})
89 89
90 90 # fill repository groups
91 91 for p in repo_group.users_group_to_perm:
92 92 data.update({'g_perm_%s' % p.users_group.users_group_name:
93 93 p.permission.permission_name})
94 94
95 95 return data
96 96
97 97 @HasPermissionAnyDecorator('hg.admin')
98 98 def index(self, format='html'):
99 99 """GET /repos_groups: All items in the collection"""
100 100 # url('repos_groups')
101 101 sk = lambda g: g.parents[0].group_name if g.parents else g.group_name
102 102 c.groups = sorted(RepoGroup.query().all(), key=sk)
103 103 return render('admin/repos_groups/repos_groups_show.html')
104 104
105 105 @HasPermissionAnyDecorator('hg.admin')
106 106 def create(self):
107 107 """POST /repos_groups: Create a new item"""
108 108 # url('repos_groups')
109 109 self.__load_defaults()
110 110 repos_group_form = ReposGroupForm(available_groups =
111 111 c.repo_groups_choices)()
112 112 try:
113 113 form_result = repos_group_form.to_python(dict(request.POST))
114 114 ReposGroupModel().create(
115 115 group_name=form_result['group_name'],
116 116 group_description=form_result['group_description'],
117 117 parent=form_result['group_parent_id']
118 118 )
119 119 Session().commit()
120 120 h.flash(_('created repos group %s') \
121 121 % form_result['group_name'], category='success')
122 122 #TODO: in futureaction_logger(, '', '', '', self.sa)
123 123 except formencode.Invalid, errors:
124 124
125 125 return htmlfill.render(
126 126 render('admin/repos_groups/repos_groups_add.html'),
127 127 defaults=errors.value,
128 128 errors=errors.error_dict or {},
129 129 prefix_error=False,
130 130 encoding="UTF-8")
131 131 except Exception:
132 132 log.error(traceback.format_exc())
133 133 h.flash(_('error occurred during creation of repos group %s') \
134 134 % request.POST.get('group_name'), category='error')
135 135
136 136 return redirect(url('repos_groups'))
137 137
138 138 @HasPermissionAnyDecorator('hg.admin')
139 139 def new(self, format='html'):
140 140 """GET /repos_groups/new: Form to create a new item"""
141 141 # url('new_repos_group')
142 142 self.__load_defaults()
143 143 return render('admin/repos_groups/repos_groups_add.html')
144 144
145 145 @HasPermissionAnyDecorator('hg.admin')
146 146 def update(self, id):
147 147 """PUT /repos_groups/id: Update an existing item"""
148 148 # Forms posted to this method should contain a hidden field:
149 149 # <input type="hidden" name="_method" value="PUT" />
150 150 # Or using helpers:
151 151 # h.form(url('repos_group', id=ID),
152 152 # method='put')
153 153 # url('repos_group', id=ID)
154 154
155 155 self.__load_defaults()
156 156 c.repos_group = RepoGroup.get(id)
157 157
158 158 repos_group_form = ReposGroupForm(
159 159 edit=True,
160 160 old_data=c.repos_group.get_dict(),
161 161 available_groups=c.repo_groups_choices
162 162 )()
163 163 try:
164 164 form_result = repos_group_form.to_python(dict(request.POST))
165 165 ReposGroupModel().update(id, form_result)
166 166 Session().commit()
167 167 h.flash(_('updated repos group %s') \
168 168 % form_result['group_name'], category='success')
169 169 #TODO: in future action_logger(, '', '', '', self.sa)
170 170 except formencode.Invalid, errors:
171 171
172 172 return htmlfill.render(
173 173 render('admin/repos_groups/repos_groups_edit.html'),
174 174 defaults=errors.value,
175 175 errors=errors.error_dict or {},
176 176 prefix_error=False,
177 177 encoding="UTF-8")
178 178 except Exception:
179 179 log.error(traceback.format_exc())
180 180 h.flash(_('error occurred during update of repos group %s') \
181 181 % request.POST.get('group_name'), category='error')
182 182
183 183 return redirect(url('edit_repos_group', id=id))
184 184
185 185 @HasPermissionAnyDecorator('hg.admin')
186 186 def delete(self, id):
187 187 """DELETE /repos_groups/id: Delete an existing item"""
188 188 # Forms posted to this method should contain a hidden field:
189 189 # <input type="hidden" name="_method" value="DELETE" />
190 190 # Or using helpers:
191 191 # h.form(url('repos_group', id=ID),
192 192 # method='delete')
193 193 # url('repos_group', id=ID)
194 194
195 195 gr = RepoGroup.get(id)
196 196 repos = gr.repositories.all()
197 197 if repos:
198 198 h.flash(_('This group contains %s repositores and cannot be '
199 199 'deleted') % len(repos),
200 200 category='error')
201 201 return redirect(url('repos_groups'))
202 202
203 203 try:
204 204 ReposGroupModel().delete(id)
205 205 Session().commit()
206 206 h.flash(_('removed repos group %s') % gr.group_name,
207 207 category='success')
208 208 #TODO: in future action_logger(, '', '', '', self.sa)
209 209 except IntegrityError, e:
210 210 if str(e.message).find('groups_group_parent_id_fkey') != -1:
211 211 log.error(traceback.format_exc())
212 212 h.flash(_('Cannot delete this group it still contains '
213 213 'subgroups'),
214 214 category='warning')
215 215 else:
216 216 log.error(traceback.format_exc())
217 217 h.flash(_('error occurred during deletion of repos '
218 218 'group %s') % gr.group_name, category='error')
219 219
220 220 except Exception:
221 221 log.error(traceback.format_exc())
222 222 h.flash(_('error occurred during deletion of repos '
223 223 'group %s') % gr.group_name, category='error')
224 224
225 225 return redirect(url('repos_groups'))
226 226
227 227 @HasReposGroupPermissionAnyDecorator('group.admin')
228 228 def delete_repos_group_user_perm(self, group_name):
229 229 """
230 230 DELETE an existing repositories group permission user
231 231
232 232 :param group_name:
233 233 """
234 234 try:
235 235 recursive = str2bool(request.POST.get('recursive', False))
236 236 ReposGroupModel().delete_permission(
237 237 repos_group=group_name, obj=request.POST['user_id'],
238 238 obj_type='user', recursive=recursive
239 239 )
240 240 Session().commit()
241 241 except Exception:
242 242 log.error(traceback.format_exc())
243 243 h.flash(_('An error occurred during deletion of group user'),
244 244 category='error')
245 245 raise HTTPInternalServerError()
246 246
247 247 @HasReposGroupPermissionAnyDecorator('group.admin')
248 248 def delete_repos_group_users_group_perm(self, group_name):
249 249 """
250 250 DELETE an existing repositories group permission users group
251 251
252 252 :param group_name:
253 253 """
254 254
255 255 try:
256 256 recursive = str2bool(request.POST.get('recursive', False))
257 257 ReposGroupModel().delete_permission(
258 258 repos_group=group_name, obj=request.POST['users_group_id'],
259 259 obj_type='users_group', recursive=recursive
260 260 )
261 261 Session().commit()
262 262 except Exception:
263 263 log.error(traceback.format_exc())
264 264 h.flash(_('An error occurred during deletion of group'
265 265 ' users groups'),
266 266 category='error')
267 267 raise HTTPInternalServerError()
268 268
269 269 def show_by_name(self, group_name):
270 270 """
271 271 This is a proxy that does a lookup group_name -> id, and shows
272 272 the group by id view instead
273 273 """
274 274 group_name = group_name.rstrip('/')
275 275 id_ = RepoGroup.get_by_group_name(group_name)
276 276 if id_:
277 277 return self.show(id_.group_id)
278 278 raise HTTPNotFound
279 279
280 280 @HasReposGroupPermissionAnyDecorator('group.read', 'group.write',
281 281 'group.admin')
282 282 def show(self, id, format='html'):
283 283 """GET /repos_groups/id: Show a specific item"""
284 284 # url('repos_group', id=ID)
285 285
286 286 c.group = RepoGroup.get_or_404(id)
287 287 c.group_repos = c.group.repositories.all()
288 288
289 289 #overwrite our cached list with current filter
290 290 gr_filter = c.group_repos
291 291 c.repo_cnt = 0
292 292
293 293 groups = RepoGroup.query().order_by(RepoGroup.group_name)\
294 294 .filter(RepoGroup.group_parent_id == id).all()
295 295 c.groups = self.scm_model.get_repos_groups(groups)
296 296
297 297 if c.visual.lightweight_dashboard is False:
298 c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter)
299
300 c.repos_list = c.cached_repo_list
298 c.repo_list = self.scm_model.get_repos(all_repos=gr_filter)
301 299 ## lightweight version of dashboard
302 300 else:
303 301 c.repos_list = Repository.query()\
304 302 .filter(Repository.group_id == id)\
305 303 .order_by(func.lower(Repository.repo_name))\
306 304 .all()
307 repos_data = []
308 total_records = len(c.repos_list)
309 305
310 _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
311 template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
312
313 quick_menu = lambda repo_name: (template.get_def("quick_menu")
314 .render(repo_name, _=_, h=h, c=c))
315 repo_lnk = lambda name, rtype, private, fork_of: (
316 template.get_def("repo_name")
317 .render(name, rtype, private, fork_of, short_name=False,
318 admin=False, _=_, h=h, c=c))
319 last_change = lambda last_change: (template.get_def("last_change")
320 .render(last_change, _=_, h=h, c=c))
321 rss_lnk = lambda repo_name: (template.get_def("rss")
322 .render(repo_name, _=_, h=h, c=c))
323 atom_lnk = lambda repo_name: (template.get_def("atom")
324 .render(repo_name, _=_, h=h, c=c))
325
326 for repo in c.repos_list:
327 repos_data.append({
328 "menu": quick_menu(repo.repo_name),
329 "raw_name": repo.repo_name.lower(),
330 "name": repo_lnk(repo.repo_name, repo.repo_type,
331 repo.private, repo.fork),
332 "last_change": last_change(repo.last_db_change),
333 "desc": repo.description,
334 "owner": h.person(repo.user.username),
335 "rss": rss_lnk(repo.repo_name),
336 "atom": atom_lnk(repo.repo_name),
337 })
338
339 c.data = json.dumps({
340 "totalRecords": total_records,
341 "startIndex": 0,
342 "sort": "name",
343 "dir": "asc",
344 "records": repos_data
345 })
306 repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
307 admin=False)
308 #json used to render the grid
309 c.data = json.dumps(repos_data)
346 310
347 311 return render('admin/repos_groups/repos_groups.html')
348 312
349 313 @HasPermissionAnyDecorator('hg.admin')
350 314 def edit(self, id, format='html'):
351 315 """GET /repos_groups/id/edit: Form to edit an existing item"""
352 316 # url('edit_repos_group', id=ID)
353 317
354 318 c.repos_group = ReposGroupModel()._get_repos_group(id)
355 319 defaults = self.__load_data(c.repos_group.group_id)
356 320
357 321 # we need to exclude this group from the group list for editing
358 322 c.repo_groups = filter(lambda x: x[0] != c.repos_group.group_id,
359 323 c.repo_groups)
360 324
361 325 return htmlfill.render(
362 326 render('admin/repos_groups/repos_groups_edit.html'),
363 327 defaults=defaults,
364 328 encoding="UTF-8",
365 329 force_defaults=False
366 330 )
@@ -1,517 +1,514 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 29 import pkg_resources
30 30 import platform
31 31
32 32 from sqlalchemy import func
33 33 from formencode import htmlfill
34 34 from pylons import request, session, tmpl_context as c, url, config
35 35 from pylons.controllers.util import abort, redirect
36 36 from pylons.i18n.translation import _
37 37
38 38 from rhodecode.lib import helpers as h
39 39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 40 HasPermissionAnyDecorator, NotAnonymous
41 41 from rhodecode.lib.base import BaseController, render
42 42 from rhodecode.lib.celerylib import tasks, run_task
43 43 from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
44 44 set_rhodecode_config, repo_name_slug, check_git_version
45 45 from rhodecode.model.db import RhodeCodeUi, Repository, RepoGroup, \
46 46 RhodeCodeSetting, PullRequest, PullRequestReviewers
47 47 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
48 48 ApplicationUiSettingsForm, ApplicationVisualisationForm
49 49 from rhodecode.model.scm import ScmModel
50 50 from rhodecode.model.user import UserModel
51 from rhodecode.model.repo import RepoModel
51 52 from rhodecode.model.db import User
52 53 from rhodecode.model.notification import EmailNotificationModel
53 54 from rhodecode.model.meta import Session
54 55 from rhodecode.lib.utils2 import str2bool, safe_unicode
55
56 from rhodecode.lib.compat import json
56 57 log = logging.getLogger(__name__)
57 58
58 59
59 60 class SettingsController(BaseController):
60 61 """REST Controller styled on the Atom Publishing Protocol"""
61 62 # To properly map this controller, ensure your config/routing.py
62 63 # file has a resource setup:
63 64 # map.resource('setting', 'settings', controller='admin/settings',
64 65 # path_prefix='/admin', name_prefix='admin_')
65 66
66 67 @LoginRequired()
67 68 def __before__(self):
68 69 c.admin_user = session.get('admin_user')
69 70 c.admin_username = session.get('admin_username')
70 71 c.modules = sorted([(p.project_name, p.version)
71 72 for p in pkg_resources.working_set]
72 73 + [('git', check_git_version())],
73 74 key=lambda k: k[0].lower())
74 75 c.py_version = platform.python_version()
75 76 c.platform = platform.platform()
76 77 super(SettingsController, self).__before__()
77 78
78 79 @HasPermissionAllDecorator('hg.admin')
79 80 def index(self, format='html'):
80 81 """GET /admin/settings: All items in the collection"""
81 82 # url('admin_settings')
82 83
83 84 defaults = RhodeCodeSetting.get_app_settings()
84 85 defaults.update(self._get_hg_ui_settings())
85 86
86 87 return htmlfill.render(
87 88 render('admin/settings/settings.html'),
88 89 defaults=defaults,
89 90 encoding="UTF-8",
90 91 force_defaults=False
91 92 )
92 93
93 94 @HasPermissionAllDecorator('hg.admin')
94 95 def create(self):
95 96 """POST /admin/settings: Create a new item"""
96 97 # url('admin_settings')
97 98
98 99 @HasPermissionAllDecorator('hg.admin')
99 100 def new(self, format='html'):
100 101 """GET /admin/settings/new: Form to create a new item"""
101 102 # url('admin_new_setting')
102 103
103 104 @HasPermissionAllDecorator('hg.admin')
104 105 def update(self, setting_id):
105 106 """PUT /admin/settings/setting_id: Update an existing item"""
106 107 # Forms posted to this method should contain a hidden field:
107 108 # <input type="hidden" name="_method" value="PUT" />
108 109 # Or using helpers:
109 110 # h.form(url('admin_setting', setting_id=ID),
110 111 # method='put')
111 112 # url('admin_setting', setting_id=ID)
112 113
113 114 if setting_id == 'mapping':
114 115 rm_obsolete = request.POST.get('destroy', False)
115 116 log.debug('Rescanning directories with destroy=%s' % rm_obsolete)
116 117 initial = ScmModel().repo_scan()
117 118 log.debug('invalidating all repositories')
118 119 for repo_name in initial.keys():
119 120 invalidate_cache('get_repo_cached_%s' % repo_name)
120 121
121 122 added, removed = repo2db_mapper(initial, rm_obsolete)
122 123 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
123 124 h.flash(_('Repositories successfully '
124 125 'rescanned added: %s ; removed: %s') %
125 126 (_repr(added), _repr(removed)),
126 127 category='success')
127 128
128 129 if setting_id == 'whoosh':
129 130 repo_location = self._get_hg_ui_settings()['paths_root_path']
130 131 full_index = request.POST.get('full_index', False)
131 132 run_task(tasks.whoosh_index, repo_location, full_index)
132 133 h.flash(_('Whoosh reindex task scheduled'), category='success')
133 134
134 135 if setting_id == 'global':
135 136
136 137 application_form = ApplicationSettingsForm()()
137 138 try:
138 139 form_result = application_form.to_python(dict(request.POST))
139 140 except formencode.Invalid, errors:
140 141 return htmlfill.render(
141 142 render('admin/settings/settings.html'),
142 143 defaults=errors.value,
143 144 errors=errors.error_dict or {},
144 145 prefix_error=False,
145 146 encoding="UTF-8"
146 147 )
147 148
148 149 try:
149 150 sett1 = RhodeCodeSetting.get_by_name_or_create('title')
150 151 sett1.app_settings_value = form_result['rhodecode_title']
151 152 Session().add(sett1)
152 153
153 154 sett2 = RhodeCodeSetting.get_by_name_or_create('realm')
154 155 sett2.app_settings_value = form_result['rhodecode_realm']
155 156 Session().add(sett2)
156 157
157 158 sett3 = RhodeCodeSetting.get_by_name_or_create('ga_code')
158 159 sett3.app_settings_value = form_result['rhodecode_ga_code']
159 160 Session().add(sett3)
160 161
161 162 Session().commit()
162 163 set_rhodecode_config(config)
163 164 h.flash(_('Updated application settings'), category='success')
164 165
165 166 except Exception:
166 167 log.error(traceback.format_exc())
167 168 h.flash(_('error occurred during updating '
168 169 'application settings'),
169 170 category='error')
170 171
171 172 if setting_id == 'visual':
172 173
173 174 application_form = ApplicationVisualisationForm()()
174 175 try:
175 176 form_result = application_form.to_python(dict(request.POST))
176 177 except formencode.Invalid, errors:
177 178 return htmlfill.render(
178 179 render('admin/settings/settings.html'),
179 180 defaults=errors.value,
180 181 errors=errors.error_dict or {},
181 182 prefix_error=False,
182 183 encoding="UTF-8"
183 184 )
184 185
185 186 try:
186 187 sett1 = RhodeCodeSetting.get_by_name_or_create('show_public_icon')
187 188 sett1.app_settings_value = \
188 189 form_result['rhodecode_show_public_icon']
189 190 Session().add(sett1)
190 191
191 192 sett2 = RhodeCodeSetting.get_by_name_or_create('show_private_icon')
192 193 sett2.app_settings_value = \
193 194 form_result['rhodecode_show_private_icon']
194 195 Session().add(sett2)
195 196
196 197 sett3 = RhodeCodeSetting.get_by_name_or_create('stylify_metatags')
197 198 sett3.app_settings_value = \
198 199 form_result['rhodecode_stylify_metatags']
199 200 Session().add(sett3)
200 201
201 202 sett4 = RhodeCodeSetting.get_by_name_or_create('lightweight_dashboard')
202 203 sett4.app_settings_value = \
203 204 form_result['rhodecode_lightweight_dashboard']
204 205 Session().add(sett4)
205 206
206 207 Session().commit()
207 208 set_rhodecode_config(config)
208 209 h.flash(_('Updated visualisation settings'),
209 210 category='success')
210 211
211 212 except Exception:
212 213 log.error(traceback.format_exc())
213 214 h.flash(_('error occurred during updating '
214 215 'visualisation settings'),
215 216 category='error')
216 217
217 218 if setting_id == 'vcs':
218 219 application_form = ApplicationUiSettingsForm()()
219 220 try:
220 221 form_result = application_form.to_python(dict(request.POST))
221 222 except formencode.Invalid, errors:
222 223 return htmlfill.render(
223 224 render('admin/settings/settings.html'),
224 225 defaults=errors.value,
225 226 errors=errors.error_dict or {},
226 227 prefix_error=False,
227 228 encoding="UTF-8"
228 229 )
229 230
230 231 try:
231 232 # fix namespaces for hooks and extensions
232 233 _f = lambda s: s.replace('.', '_')
233 234
234 235 sett = RhodeCodeUi.get_by_key('push_ssl')
235 236 sett.ui_value = form_result['web_push_ssl']
236 237 Session().add(sett)
237 238
238 239 sett = RhodeCodeUi.get_by_key('/')
239 240 sett.ui_value = form_result['paths_root_path']
240 241 Session().add(sett)
241 242
242 243 #HOOKS
243 244 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_UPDATE)
244 245 sett.ui_active = form_result[_f('hooks_%s' %
245 246 RhodeCodeUi.HOOK_UPDATE)]
246 247 Session().add(sett)
247 248
248 249 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_REPO_SIZE)
249 250 sett.ui_active = form_result[_f('hooks_%s' %
250 251 RhodeCodeUi.HOOK_REPO_SIZE)]
251 252 Session().add(sett)
252 253
253 254 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_PUSH)
254 255 sett.ui_active = form_result[_f('hooks_%s' %
255 256 RhodeCodeUi.HOOK_PUSH)]
256 257 Session().add(sett)
257 258
258 259 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_PULL)
259 260 sett.ui_active = form_result[_f('hooks_%s' %
260 261 RhodeCodeUi.HOOK_PULL)]
261 262
262 263 Session().add(sett)
263 264
264 265 ## EXTENSIONS
265 266 sett = RhodeCodeUi.get_by_key('largefiles')
266 267 if not sett:
267 268 #make one if it's not there !
268 269 sett = RhodeCodeUi()
269 270 sett.ui_key = 'largefiles'
270 271 sett.ui_section = 'extensions'
271 272 sett.ui_active = form_result[_f('extensions_largefiles')]
272 273 Session().add(sett)
273 274
274 275 sett = RhodeCodeUi.get_by_key('hgsubversion')
275 276 if not sett:
276 277 #make one if it's not there !
277 278 sett = RhodeCodeUi()
278 279 sett.ui_key = 'hgsubversion'
279 280 sett.ui_section = 'extensions'
280 281
281 282 sett.ui_active = form_result[_f('extensions_hgsubversion')]
282 283 Session().add(sett)
283 284
284 285 # sett = RhodeCodeUi.get_by_key('hggit')
285 286 # if not sett:
286 287 # #make one if it's not there !
287 288 # sett = RhodeCodeUi()
288 289 # sett.ui_key = 'hggit'
289 290 # sett.ui_section = 'extensions'
290 291 #
291 292 # sett.ui_active = form_result[_f('extensions_hggit')]
292 293 # Session().add(sett)
293 294
294 295 Session().commit()
295 296
296 297 h.flash(_('Updated VCS settings'), category='success')
297 298
298 299 except Exception:
299 300 log.error(traceback.format_exc())
300 301 h.flash(_('error occurred during updating '
301 302 'application settings'), category='error')
302 303
303 304 if setting_id == 'hooks':
304 305 ui_key = request.POST.get('new_hook_ui_key')
305 306 ui_value = request.POST.get('new_hook_ui_value')
306 307 try:
307 308
308 309 if ui_value and ui_key:
309 310 RhodeCodeUi.create_or_update_hook(ui_key, ui_value)
310 311 h.flash(_('Added new hook'),
311 312 category='success')
312 313
313 314 # check for edits
314 315 update = False
315 316 _d = request.POST.dict_of_lists()
316 317 for k, v in zip(_d.get('hook_ui_key', []),
317 318 _d.get('hook_ui_value_new', [])):
318 319 RhodeCodeUi.create_or_update_hook(k, v)
319 320 update = True
320 321
321 322 if update:
322 323 h.flash(_('Updated hooks'), category='success')
323 324 Session().commit()
324 325 except Exception:
325 326 log.error(traceback.format_exc())
326 327 h.flash(_('error occurred during hook creation'),
327 328 category='error')
328 329
329 330 return redirect(url('admin_edit_setting', setting_id='hooks'))
330 331
331 332 if setting_id == 'email':
332 333 test_email = request.POST.get('test_email')
333 334 test_email_subj = 'RhodeCode TestEmail'
334 335 test_email_body = 'RhodeCode Email test'
335 336
336 337 test_email_html_body = EmailNotificationModel()\
337 338 .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT,
338 339 body=test_email_body)
339 340
340 341 recipients = [test_email] if test_email else None
341 342
342 343 run_task(tasks.send_email, recipients, test_email_subj,
343 344 test_email_body, test_email_html_body)
344 345
345 346 h.flash(_('Email task created'), category='success')
346 347 return redirect(url('admin_settings'))
347 348
348 349 @HasPermissionAllDecorator('hg.admin')
349 350 def delete(self, setting_id):
350 351 """DELETE /admin/settings/setting_id: Delete an existing item"""
351 352 # Forms posted to this method should contain a hidden field:
352 353 # <input type="hidden" name="_method" value="DELETE" />
353 354 # Or using helpers:
354 355 # h.form(url('admin_setting', setting_id=ID),
355 356 # method='delete')
356 357 # url('admin_setting', setting_id=ID)
357 358 if setting_id == 'hooks':
358 359 hook_id = request.POST.get('hook_id')
359 360 RhodeCodeUi.delete(hook_id)
360 361 Session().commit()
361 362
362 363 @HasPermissionAllDecorator('hg.admin')
363 364 def show(self, setting_id, format='html'):
364 365 """
365 366 GET /admin/settings/setting_id: Show a specific item"""
366 367 # url('admin_setting', setting_id=ID)
367 368
368 369 @HasPermissionAllDecorator('hg.admin')
369 370 def edit(self, setting_id, format='html'):
370 371 """
371 372 GET /admin/settings/setting_id/edit: Form to
372 373 edit an existing item"""
373 374 # url('admin_edit_setting', setting_id=ID)
374 375
375 376 c.hooks = RhodeCodeUi.get_builtin_hooks()
376 377 c.custom_hooks = RhodeCodeUi.get_custom_hooks()
377 378
378 379 return htmlfill.render(
379 380 render('admin/settings/hooks.html'),
380 381 defaults={},
381 382 encoding="UTF-8",
382 383 force_defaults=False
383 384 )
384 385
385 386 @NotAnonymous()
386 387 def my_account(self):
387 388 """
388 389 GET /_admin/my_account Displays info about my account
389 390 """
390 391 # url('admin_settings_my_account')
391 392
392 393 c.user = User.get(self.rhodecode_user.user_id)
393 all_repos = Session().query(Repository)\
394 .filter(Repository.user_id == c.user.user_id)\
395 .order_by(func.lower(Repository.repo_name)).all()
396
397 c.user_repos = ScmModel().get_repos(all_repos)
398 394
399 395 if c.user.username == 'default':
400 396 h.flash(_("You can't edit this user since it's"
401 397 " crucial for entire application"), category='warning')
402 398 return redirect(url('users'))
403 399
400 repos_list = Session().query(Repository)\
401 .filter(Repository.user_id ==
402 self.rhodecode_user.user_id)\
403 .order_by(func.lower(Repository.repo_name)).all()
404
405 repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list,
406 admin=True)
407 #json used to render the grid
408 c.data = json.dumps(repos_data)
409
404 410 defaults = c.user.get_dict()
405 411
406 412 c.form = htmlfill.render(
407 413 render('admin/users/user_edit_my_account_form.html'),
408 414 defaults=defaults,
409 415 encoding="UTF-8",
410 416 force_defaults=False
411 417 )
412 418 return render('admin/users/user_edit_my_account.html')
413 419
414 420 @NotAnonymous()
415 421 def my_account_update(self):
416 422 """PUT /_admin/my_account_update: Update an existing item"""
417 423 # Forms posted to this method should contain a hidden field:
418 424 # <input type="hidden" name="_method" value="PUT" />
419 425 # Or using helpers:
420 426 # h.form(url('admin_settings_my_account_update'),
421 427 # method='put')
422 428 # url('admin_settings_my_account_update', id=ID)
423 429 uid = self.rhodecode_user.user_id
424 430 email = self.rhodecode_user.email
425 431 _form = UserForm(edit=True,
426 432 old_data={'user_id': uid, 'email': email})()
427 433 form_result = {}
428 434 try:
429 435 form_result = _form.to_python(dict(request.POST))
430 436 UserModel().update_my_account(uid, form_result)
431 437 h.flash(_('Your account was updated successfully'),
432 438 category='success')
433 439 Session().commit()
434 440 except formencode.Invalid, errors:
435 441 c.user = User.get(self.rhodecode_user.user_id)
436 442
437 443 c.form = htmlfill.render(
438 444 render('admin/users/user_edit_my_account_form.html'),
439 445 defaults=errors.value,
440 446 errors=errors.error_dict or {},
441 447 prefix_error=False,
442 448 encoding="UTF-8")
443 449 return render('admin/users/user_edit_my_account.html')
444 450 except Exception:
445 451 log.error(traceback.format_exc())
446 452 h.flash(_('error occurred during update of user %s') \
447 453 % form_result.get('username'), category='error')
448 454
449 455 return redirect(url('my_account'))
450 456
451 457 @NotAnonymous()
452 def my_account_my_repos(self):
453 all_repos = Session().query(Repository)\
454 .filter(Repository.user_id == self.rhodecode_user.user_id)\
455 .order_by(func.lower(Repository.repo_name))\
456 .all()
457 c.user_repos = ScmModel().get_repos(all_repos)
458 return render('admin/users/user_edit_my_account_repos.html')
459
460 @NotAnonymous()
461 458 def my_account_my_pullrequests(self):
462 459 c.my_pull_requests = PullRequest.query()\
463 460 .filter(PullRequest.user_id==
464 461 self.rhodecode_user.user_id)\
465 462 .all()
466 463 c.participate_in_pull_requests = \
467 464 [x.pull_request for x in PullRequestReviewers.query()\
468 465 .filter(PullRequestReviewers.user_id==
469 466 self.rhodecode_user.user_id)\
470 467 .all()]
471 468 return render('admin/users/user_edit_my_account_pullrequests.html')
472 469
473 470 @NotAnonymous()
474 471 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
475 472 def create_repository(self):
476 473 """GET /_admin/create_repository: Form to create a new item"""
477 474
478 475 c.repo_groups = RepoGroup.groups_choices(check_perms=True)
479 476 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
480 477 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
481 478
482 479 new_repo = request.GET.get('repo', '')
483 480 c.new_repo = repo_name_slug(new_repo)
484 481
485 482 ## apply the defaults from defaults page
486 483 defaults = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
487 484 return htmlfill.render(
488 485 render('admin/repos/repo_add_create_repository.html'),
489 486 defaults=defaults,
490 487 errors={},
491 488 prefix_error=False,
492 489 encoding="UTF-8"
493 490 )
494 491
495 492 def _get_hg_ui_settings(self):
496 493 ret = RhodeCodeUi.query().all()
497 494
498 495 if not ret:
499 496 raise Exception('Could not get application ui settings !')
500 497 settings = {}
501 498 for each in ret:
502 499 k = each.ui_key
503 500 v = each.ui_value
504 501 if k == '/':
505 502 k = 'root_path'
506 503
507 504 if k == 'push_ssl':
508 505 v = str2bool(v)
509 506
510 507 if k.find('.') != -1:
511 508 k = k.replace('.', '_')
512 509
513 510 if each.ui_section in ['hooks', 'extensions']:
514 511 v = each.ui_active
515 512
516 513 settings[each.ui_section + '_' + k] = v
517 514 return settings
@@ -1,133 +1,87 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.home
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Home controller for Rhodecode
7 7
8 8 :created_on: Feb 18, 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
28 28 from pylons import tmpl_context as c, request
29 29 from pylons.i18n.translation import _
30 30 from webob.exc import HTTPBadRequest
31 from sqlalchemy.sql.expression import func
31 32
32 33 import rhodecode
33 34 from rhodecode.lib import helpers as h
34 35 from rhodecode.lib.ext_json import json
35 36 from rhodecode.lib.auth import LoginRequired
36 37 from rhodecode.lib.base import BaseController, render
37 38 from rhodecode.model.db import Repository
38 from sqlalchemy.sql.expression import func
39 from rhodecode.model.repo import RepoModel
40
39 41
40 42 log = logging.getLogger(__name__)
41 43
42 44
43 45 class HomeController(BaseController):
44 46
45 47 @LoginRequired()
46 48 def __before__(self):
47 49 super(HomeController, self).__before__()
48 50
49 51 def index(self):
50 52 c.groups = self.scm_model.get_repos_groups()
51 53 c.group = None
52 54
53 55 if c.visual.lightweight_dashboard is False:
54 56 c.repos_list = self.scm_model.get_repos()
55 57 ## lightweight version of dashboard
56 58 else:
57 59 c.repos_list = Repository.query()\
58 60 .filter(Repository.group_id == None)\
59 61 .order_by(func.lower(Repository.repo_name))\
60 62 .all()
61 repos_data = []
62 total_records = len(c.repos_list)
63 63
64 _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
65 template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
66
67 quick_menu = lambda repo_name: (template.get_def("quick_menu")
68 .render(repo_name, _=_, h=h, c=c))
69 repo_lnk = lambda name, rtype, private, fork_of: (
70 template.get_def("repo_name")
71 .render(name, rtype, private, fork_of, short_name=False,
72 admin=False, _=_, h=h, c=c))
73 last_change = lambda last_change: (template.get_def("last_change")
74 .render(last_change, _=_, h=h, c=c))
75 rss_lnk = lambda repo_name: (template.get_def("rss")
76 .render(repo_name, _=_, h=h, c=c))
77 atom_lnk = lambda repo_name: (template.get_def("atom")
78 .render(repo_name, _=_, h=h, c=c))
79 tip = lambda repo_name, cs_cache: (template.get_def("revision")
80 .render(repo_name,
81 cs_cache.get('revision'),
82 cs_cache.get('raw_id'),
83 cs_cache.get('author'),
84 cs_cache.get('message'), _=_, h=h,
85 c=c))
86
87 def desc(desc):
88 if c.visual.stylify_metatags:
89 return h.urlify_text(h.desc_stylize(h.truncate(desc, 60)))
90 else:
91 return h.urlify_text(h.truncate(desc, 60))
92
93 for repo in c.repos_list:
94 repos_data.append({
95 "menu": quick_menu(repo.repo_name),
96 "raw_name": repo.repo_name.lower(),
97 "name": repo_lnk(repo.repo_name, repo.repo_type,
98 repo.private, repo.fork),
99 "last_change": last_change(repo.last_db_change),
100 "tip": tip(repo.repo_name, repo.changeset_cache),
101 "desc": desc(repo.description),
102 "owner": h.person(repo.user.username),
103 "rss": rss_lnk(repo.repo_name),
104 "atom": atom_lnk(repo.repo_name),
105 })
106
107 c.data = json.dumps({
108 "totalRecords": total_records,
109 "startIndex": 0,
110 "sort": "name",
111 "dir": "asc",
112 "records": repos_data
113 })
64 repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
65 admin=False)
66 #json used to render the grid
67 c.data = json.dumps(repos_data)
114 68
115 69 return render('/index.html')
116 70
117 71 def repo_switcher(self):
118 72 if request.is_xhr:
119 73 all_repos = Repository.query().order_by(Repository.repo_name).all()
120 74 c.repos_list = self.scm_model.get_repos(all_repos,
121 75 sort_key='name_sort',
122 76 simple=True)
123 77 return render('/repo_switcher_list.html')
124 78 else:
125 79 raise HTTPBadRequest()
126 80
127 81 def branch_tag_switcher(self, repo_name):
128 82 if request.is_xhr:
129 83 c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name)
130 84 c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
131 85 return render('/switch_to_list.html')
132 86 else:
133 87 raise HTTPBadRequest()
@@ -1,322 +1,379 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.journal
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Journal controller for pylons
7 7
8 8 :created_on: Nov 21, 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 import logging
26 26 from itertools import groupby
27 27
28 28 from sqlalchemy import or_
29 29 from sqlalchemy.orm import joinedload
30 from sqlalchemy.sql.expression import func
31
30 32 from webhelpers.paginate import Page
31 33 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
32 34
33 35 from webob.exc import HTTPBadRequest
34 36 from pylons import request, tmpl_context as c, response, url
35 37 from pylons.i18n.translation import _
36 38
37 39 import rhodecode.lib.helpers as h
38 40 from rhodecode.lib.auth import LoginRequired, NotAnonymous
39 41 from rhodecode.lib.base import BaseController, render
40 42 from rhodecode.model.db import UserLog, UserFollowing, Repository, User
41 43 from rhodecode.model.meta import Session
42 from sqlalchemy.sql.expression import func
43 from rhodecode.model.scm import ScmModel
44 44 from rhodecode.lib.utils2 import safe_int, AttributeDict
45 45 from rhodecode.controllers.admin.admin import _journal_filter
46 from rhodecode.model.repo import RepoModel
47 from rhodecode.lib.compat import json
46 48
47 49 log = logging.getLogger(__name__)
48 50
49 51
50 52 class JournalController(BaseController):
51 53
52 54 def __before__(self):
53 55 super(JournalController, self).__before__()
54 56 self.language = 'en-us'
55 57 self.ttl = "5"
56 58 self.feed_nr = 20
57 59 c.search_term = request.GET.get('filter')
58 60
59 61 @LoginRequired()
60 62 @NotAnonymous()
61 63 def index(self):
62 64 # Return a rendered template
63 65 p = safe_int(request.params.get('page', 1), 1)
64 66 c.user = User.get(self.rhodecode_user.user_id)
65 67 c.following = self.sa.query(UserFollowing)\
66 68 .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
67 69 .options(joinedload(UserFollowing.follows_repository))\
68 70 .all()
69 71
70 72 journal = self._get_journal_data(c.following)
71 73
72 74 def url_generator(**kw):
73 75 return url.current(filter=c.search_term, **kw)
74 76
75 77 c.journal_pager = Page(journal, page=p, items_per_page=20, url=url_generator)
76 78 c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
77 79
78 80 c.journal_data = render('journal/journal_data.html')
79 81 if request.environ.get('HTTP_X_PARTIAL_XHR'):
80 82 return c.journal_data
81 return render('journal/journal.html')
83
84 repos_list = Session().query(Repository)\
85 .filter(Repository.user_id ==
86 self.rhodecode_user.user_id)\
87 .order_by(func.lower(Repository.repo_name)).all()
88
89 repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list,
90 admin=True)
91 #json used to render the grid
92 c.data = json.dumps(repos_data)
93
94 watched_repos_data = []
95
96 ## watched repos
97 _render = RepoModel._render_datatable
98
99 def quick_menu(repo_name):
100 return _render('quick_menu', repo_name)
101
102 def repo_lnk(name, rtype, private, fork_of):
103 return _render('repo_name', name, rtype, private, fork_of,
104 short_name=False, admin=False)
105
106 def last_rev(repo_name, cs_cache):
107 return _render('revision', repo_name, cs_cache.get('revision'),
108 cs_cache.get('raw_id'), cs_cache.get('author'),
109 cs_cache.get('message'))
82 110
83 @LoginRequired()
84 @NotAnonymous()
85 def index_my_repos(self):
86 c.user = User.get(self.rhodecode_user.user_id)
87 if request.environ.get('HTTP_X_PARTIAL_XHR'):
88 all_repos = self.sa.query(Repository)\
89 .filter(Repository.user_id == c.user.user_id)\
90 .order_by(func.lower(Repository.repo_name)).all()
91 c.user_repos = ScmModel().get_repos(all_repos)
92 return render('journal/journal_page_repos.html')
111 def desc(desc):
112 from pylons import tmpl_context as c
113 if c.visual.stylify_metatags:
114 return h.urlify_text(h.desc_stylize(h.truncate(desc, 60)))
115 else:
116 return h.urlify_text(h.truncate(desc, 60))
117
118 def repo_actions(repo_name):
119 return _render('repo_actions', repo_name)
120
121 def owner_actions(user_id, username):
122 return _render('user_name', user_id, username)
123
124 def toogle_follow(repo_id):
125 return _render('toggle_follow', repo_id)
126
127 for entry in c.following:
128 repo = entry.follows_repository
129 cs_cache = repo.changeset_cache
130 row = {
131 "menu": quick_menu(repo.repo_name),
132 "raw_name": repo.repo_name.lower(),
133 "name": repo_lnk(repo.repo_name, repo.repo_type,
134 repo.private, repo.fork),
135 "last_changeset": last_rev(repo.repo_name, cs_cache),
136 "raw_tip": cs_cache.get('revision'),
137 "action": toogle_follow(repo.repo_id)
138 }
139
140 watched_repos_data.append(row)
141
142 c.watched_data = json.dumps({
143 "totalRecords": len(c.following),
144 "startIndex": 0,
145 "sort": "name",
146 "dir": "asc",
147 "records": watched_repos_data
148 })
149 return render('journal/journal.html')
93 150
94 151 @LoginRequired(api_access=True)
95 152 @NotAnonymous()
96 153 def journal_atom(self):
97 154 """
98 155 Produce an atom-1.0 feed via feedgenerator module
99 156 """
100 157 following = self.sa.query(UserFollowing)\
101 158 .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
102 159 .options(joinedload(UserFollowing.follows_repository))\
103 160 .all()
104 161 return self._atom_feed(following, public=False)
105 162
106 163 @LoginRequired(api_access=True)
107 164 @NotAnonymous()
108 165 def journal_rss(self):
109 166 """
110 167 Produce an rss feed via feedgenerator module
111 168 """
112 169 following = self.sa.query(UserFollowing)\
113 170 .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
114 171 .options(joinedload(UserFollowing.follows_repository))\
115 172 .all()
116 173 return self._rss_feed(following, public=False)
117 174
118 175 def _get_daily_aggregate(self, journal):
119 176 groups = []
120 177 for k, g in groupby(journal, lambda x: x.action_as_day):
121 178 user_group = []
122 179 #groupby username if it's a present value, else fallback to journal username
123 180 for _, g2 in groupby(list(g), lambda x: x.user.username if x.user else x.username):
124 181 l = list(g2)
125 182 user_group.append((l[0].user, l))
126 183
127 184 groups.append((k, user_group,))
128 185
129 186 return groups
130 187
131 188 def _get_journal_data(self, following_repos):
132 189 repo_ids = [x.follows_repository.repo_id for x in following_repos
133 190 if x.follows_repository is not None]
134 191 user_ids = [x.follows_user.user_id for x in following_repos
135 192 if x.follows_user is not None]
136 193
137 194 filtering_criterion = None
138 195
139 196 if repo_ids and user_ids:
140 197 filtering_criterion = or_(UserLog.repository_id.in_(repo_ids),
141 198 UserLog.user_id.in_(user_ids))
142 199 if repo_ids and not user_ids:
143 200 filtering_criterion = UserLog.repository_id.in_(repo_ids)
144 201 if not repo_ids and user_ids:
145 202 filtering_criterion = UserLog.user_id.in_(user_ids)
146 203 if filtering_criterion is not None:
147 204 journal = self.sa.query(UserLog)\
148 205 .options(joinedload(UserLog.user))\
149 206 .options(joinedload(UserLog.repository))
150 207 #filter
151 208 try:
152 209 journal = _journal_filter(journal, c.search_term)
153 210 except:
154 211 # we want this to crash for now
155 212 raise
156 213 journal = journal.filter(filtering_criterion)\
157 214 .order_by(UserLog.action_date.desc())
158 215 else:
159 216 journal = []
160 217
161 218 return journal
162 219
163 220 @LoginRequired()
164 221 @NotAnonymous()
165 222 def toggle_following(self):
166 223 cur_token = request.POST.get('auth_token')
167 224 token = h.get_token()
168 225 if cur_token == token:
169 226
170 227 user_id = request.POST.get('follows_user_id')
171 228 if user_id:
172 229 try:
173 230 self.scm_model.toggle_following_user(user_id,
174 231 self.rhodecode_user.user_id)
175 232 Session.commit()
176 233 return 'ok'
177 234 except:
178 235 raise HTTPBadRequest()
179 236
180 237 repo_id = request.POST.get('follows_repo_id')
181 238 if repo_id:
182 239 try:
183 240 self.scm_model.toggle_following_repo(repo_id,
184 241 self.rhodecode_user.user_id)
185 242 Session.commit()
186 243 return 'ok'
187 244 except:
188 245 raise HTTPBadRequest()
189 246
190 247 log.debug('token mismatch %s vs %s' % (cur_token, token))
191 248 raise HTTPBadRequest()
192 249
193 250 @LoginRequired()
194 251 def public_journal(self):
195 252 # Return a rendered template
196 253 p = safe_int(request.params.get('page', 1), 1)
197 254
198 255 c.following = self.sa.query(UserFollowing)\
199 256 .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
200 257 .options(joinedload(UserFollowing.follows_repository))\
201 258 .all()
202 259
203 260 journal = self._get_journal_data(c.following)
204 261
205 262 c.journal_pager = Page(journal, page=p, items_per_page=20)
206 263
207 264 c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
208 265
209 266 c.journal_data = render('journal/journal_data.html')
210 267 if request.environ.get('HTTP_X_PARTIAL_XHR'):
211 268 return c.journal_data
212 269 return render('journal/public_journal.html')
213 270
214 271 def _atom_feed(self, repos, public=True):
215 272 journal = self._get_journal_data(repos)
216 273 if public:
217 274 _link = url('public_journal_atom', qualified=True)
218 275 _desc = '%s %s %s' % (c.rhodecode_name, _('public journal'),
219 276 'atom feed')
220 277 else:
221 278 _link = url('journal_atom', qualified=True)
222 279 _desc = '%s %s %s' % (c.rhodecode_name, _('journal'), 'atom feed')
223 280
224 281 feed = Atom1Feed(title=_desc,
225 282 link=_link,
226 283 description=_desc,
227 284 language=self.language,
228 285 ttl=self.ttl)
229 286
230 287 for entry in journal[:self.feed_nr]:
231 288 user = entry.user
232 289 if user is None:
233 290 #fix deleted users
234 291 user = AttributeDict({'short_contact': entry.username,
235 292 'email': '',
236 293 'full_contact': ''})
237 294 action, action_extra, ico = h.action_parser(entry, feed=True)
238 295 title = "%s - %s %s" % (user.short_contact, action(),
239 296 entry.repository.repo_name)
240 297 desc = action_extra()
241 298 _url = None
242 299 if entry.repository is not None:
243 300 _url = url('changelog_home',
244 301 repo_name=entry.repository.repo_name,
245 302 qualified=True)
246 303
247 304 feed.add_item(title=title,
248 305 pubdate=entry.action_date,
249 306 link=_url or url('', qualified=True),
250 307 author_email=user.email,
251 308 author_name=user.full_contact,
252 309 description=desc)
253 310
254 311 response.content_type = feed.mime_type
255 312 return feed.writeString('utf-8')
256 313
257 314 def _rss_feed(self, repos, public=True):
258 315 journal = self._get_journal_data(repos)
259 316 if public:
260 317 _link = url('public_journal_atom', qualified=True)
261 318 _desc = '%s %s %s' % (c.rhodecode_name, _('public journal'),
262 319 'rss feed')
263 320 else:
264 321 _link = url('journal_atom', qualified=True)
265 322 _desc = '%s %s %s' % (c.rhodecode_name, _('journal'), 'rss feed')
266 323
267 324 feed = Rss201rev2Feed(title=_desc,
268 325 link=_link,
269 326 description=_desc,
270 327 language=self.language,
271 328 ttl=self.ttl)
272 329
273 330 for entry in journal[:self.feed_nr]:
274 331 user = entry.user
275 332 if user is None:
276 333 #fix deleted users
277 334 user = AttributeDict({'short_contact': entry.username,
278 335 'email': '',
279 336 'full_contact': ''})
280 337 action, action_extra, ico = h.action_parser(entry, feed=True)
281 338 title = "%s - %s %s" % (user.short_contact, action(),
282 339 entry.repository.repo_name)
283 340 desc = action_extra()
284 341 _url = None
285 342 if entry.repository is not None:
286 343 _url = url('changelog_home',
287 344 repo_name=entry.repository.repo_name,
288 345 qualified=True)
289 346
290 347 feed.add_item(title=title,
291 348 pubdate=entry.action_date,
292 349 link=_url or url('', qualified=True),
293 350 author_email=user.email,
294 351 author_name=user.full_contact,
295 352 description=desc)
296 353
297 354 response.content_type = feed.mime_type
298 355 return feed.writeString('utf-8')
299 356
300 357 @LoginRequired(api_access=True)
301 358 def public_journal_atom(self):
302 359 """
303 360 Produce an atom-1.0 feed via feedgenerator module
304 361 """
305 362 c.following = self.sa.query(UserFollowing)\
306 363 .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
307 364 .options(joinedload(UserFollowing.follows_repository))\
308 365 .all()
309 366
310 367 return self._atom_feed(c.following)
311 368
312 369 @LoginRequired(api_access=True)
313 370 def public_journal_rss(self):
314 371 """
315 372 Produce an rss2 feed via feedgenerator module
316 373 """
317 374 c.following = self.sa.query(UserFollowing)\
318 375 .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
319 376 .options(joinedload(UserFollowing.follows_repository))\
320 377 .all()
321 378
322 379 return self._rss_feed(c.following)
@@ -1,579 +1,669 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.repo
4 4 ~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Repository model for rhodecode
7 7
8 8 :created_on: Jun 5, 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 from __future__ import with_statement
26 26 import os
27 27 import shutil
28 28 import logging
29 29 import traceback
30 30 from datetime import datetime
31 31
32 32 from rhodecode.lib.vcs.backends import get_backend
33 33 from rhodecode.lib.compat import json
34 34 from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode,\
35 35 remove_prefix
36 36 from rhodecode.lib.caching_query import FromCache
37 37 from rhodecode.lib.hooks import log_create_repository, log_delete_repository
38 38
39 39 from rhodecode.model import BaseModel
40 40 from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
41 41 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup,\
42 42 RhodeCodeSetting
43 43 from rhodecode.lib import helpers as h
44 from rhodecode.lib.auth import HasRepoPermissionAny
44 45
45 46
46 47 log = logging.getLogger(__name__)
47 48
48 49
49 50 class RepoModel(BaseModel):
50 51
51 52 cls = Repository
52 53 URL_SEPARATOR = Repository.url_sep()
53 54
54 55 def __get_users_group(self, users_group):
55 56 return self._get_instance(UsersGroup, users_group,
56 57 callback=UsersGroup.get_by_group_name)
57 58
58 59 def _get_repos_group(self, repos_group):
59 60 return self._get_instance(RepoGroup, repos_group,
60 61 callback=RepoGroup.get_by_group_name)
61 62
62 63 @LazyProperty
63 64 def repos_path(self):
64 65 """
65 66 Get's the repositories root path from database
66 67 """
67 68
68 69 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
69 70 return q.ui_value
70 71
71 72 def get(self, repo_id, cache=False):
72 73 repo = self.sa.query(Repository)\
73 74 .filter(Repository.repo_id == repo_id)
74 75
75 76 if cache:
76 77 repo = repo.options(FromCache("sql_cache_short",
77 78 "get_repo_%s" % repo_id))
78 79 return repo.scalar()
79 80
80 81 def get_repo(self, repository):
81 82 return self._get_repo(repository)
82 83
83 84 def get_by_repo_name(self, repo_name, cache=False):
84 85 repo = self.sa.query(Repository)\
85 86 .filter(Repository.repo_name == repo_name)
86 87
87 88 if cache:
88 89 repo = repo.options(FromCache("sql_cache_short",
89 90 "get_repo_%s" % repo_name))
90 91 return repo.scalar()
91 92
92 93 def get_users_js(self):
93 94 users = self.sa.query(User).filter(User.active == True).all()
94 95 return json.dumps([
95 96 {
96 97 'id': u.user_id,
97 98 'fname': u.name,
98 99 'lname': u.lastname,
99 100 'nname': u.username,
100 101 'gravatar_lnk': h.gravatar_url(u.email, 14)
101 102 } for u in users]
102 103 )
103 104
104 105 def get_users_groups_js(self):
105 106 users_groups = self.sa.query(UsersGroup)\
106 107 .filter(UsersGroup.users_group_active == True).all()
107 108
108 109 return json.dumps([
109 110 {
110 111 'id': gr.users_group_id,
111 112 'grname': gr.users_group_name,
112 113 'grmembers': len(gr.members),
113 114 } for gr in users_groups]
114 115 )
115 116
117 @classmethod
118 def _render_datatable(cls, tmpl, *args, **kwargs):
119 import rhodecode
120 from pylons import tmpl_context as c
121 from pylons.i18n.translation import _
122
123 _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
124 template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
125
126 tmpl = template.get_def(tmpl)
127 kwargs.update(dict(_=_, h=h, c=c))
128 return tmpl.render(*args, **kwargs)
129
130 def get_repos_as_dict(self, repos_list=None, admin=False, perm_check=True):
131 _render = self._render_datatable
132
133 def quick_menu(repo_name):
134 return _render('quick_menu', repo_name)
135
136 def repo_lnk(name, rtype, private, fork_of):
137 return _render('repo_name', name, rtype, private, fork_of,
138 short_name=not admin, admin=False)
139
140 def last_change(last_change):
141 return _render("last_change", last_change)
142
143 def rss_lnk(repo_name):
144 return _render("rss", repo_name)
145
146 def atom_lnk(repo_name):
147 return _render("atom", repo_name)
148
149 def last_rev(repo_name, cs_cache):
150 return _render('revision', repo_name, cs_cache.get('revision'),
151 cs_cache.get('raw_id'), cs_cache.get('author'),
152 cs_cache.get('message'))
153
154 def desc(desc):
155 from pylons import tmpl_context as c
156 if c.visual.stylify_metatags:
157 return h.urlify_text(h.desc_stylize(h.truncate(desc, 60)))
158 else:
159 return h.urlify_text(h.truncate(desc, 60))
160
161 def repo_actions(repo_name):
162 return _render('repo_actions', repo_name)
163
164 def owner_actions(user_id, username):
165 return _render('user_name', user_id, username)
166
167 repos_data = []
168 for repo in repos_list:
169 if perm_check:
170 # check permission at this level
171 if not HasRepoPermissionAny(
172 'repository.read', 'repository.write', 'repository.admin'
173 )(repo.repo_name, 'get_repos_as_dict check'):
174 continue
175 cs_cache = repo.changeset_cache
176 row = {
177 "menu": quick_menu(repo.repo_name),
178 "raw_name": repo.repo_name.lower(),
179 "name": repo_lnk(repo.repo_name, repo.repo_type,
180 repo.private, repo.fork),
181 "last_change": last_change(repo.last_db_change),
182 "last_changeset": last_rev(repo.repo_name, cs_cache),
183 "raw_tip": cs_cache.get('revision'),
184 "desc": desc(repo.description),
185 "owner": h.person(repo.user.username),
186 "rss": rss_lnk(repo.repo_name),
187 "atom": atom_lnk(repo.repo_name),
188
189 }
190 if admin:
191 row.update({
192 "action": repo_actions(repo.repo_name),
193 "owner": owner_actions(repo.user.user_id,
194 h.person(repo.user.username))
195 })
196 repos_data.append(row)
197
198 return {
199 "totalRecords": len(repos_list),
200 "startIndex": 0,
201 "sort": "name",
202 "dir": "asc",
203 "records": repos_data
204 }
205
116 206 def _get_defaults(self, repo_name):
117 207 """
118 208 Get's information about repository, and returns a dict for
119 209 usage in forms
120 210
121 211 :param repo_name:
122 212 """
123 213
124 214 repo_info = Repository.get_by_repo_name(repo_name)
125 215
126 216 if repo_info is None:
127 217 return None
128 218
129 219 defaults = repo_info.get_dict()
130 220 group, repo_name = repo_info.groups_and_repo
131 221 defaults['repo_name'] = repo_name
132 222 defaults['repo_group'] = getattr(group[-1] if group else None,
133 223 'group_id', None)
134 224
135 225 for strip, k in [(0, 'repo_type'), (1, 'repo_enable_downloads'),
136 226 (1, 'repo_description'), (1, 'repo_enable_locking'),
137 227 (1, 'repo_landing_rev'), (0, 'clone_uri'),
138 228 (1, 'repo_private'), (1, 'repo_enable_statistics')]:
139 229 attr = k
140 230 if strip:
141 231 attr = remove_prefix(k, 'repo_')
142 232
143 233 defaults[k] = defaults[attr]
144 234
145 235 # fill owner
146 236 if repo_info.user:
147 237 defaults.update({'user': repo_info.user.username})
148 238 else:
149 239 replacement_user = User.query().filter(User.admin ==
150 240 True).first().username
151 241 defaults.update({'user': replacement_user})
152 242
153 243 # fill repository users
154 244 for p in repo_info.repo_to_perm:
155 245 defaults.update({'u_perm_%s' % p.user.username:
156 246 p.permission.permission_name})
157 247
158 248 # fill repository groups
159 249 for p in repo_info.users_group_to_perm:
160 250 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
161 251 p.permission.permission_name})
162 252
163 253 return defaults
164 254
165 255 def update(self, org_repo_name, **kwargs):
166 256 try:
167 257 cur_repo = self.get_by_repo_name(org_repo_name, cache=False)
168 258
169 259 # update permissions
170 260 for member, perm, member_type in kwargs['perms_updates']:
171 261 if member_type == 'user':
172 262 # this updates existing one
173 263 RepoModel().grant_user_permission(
174 264 repo=cur_repo, user=member, perm=perm
175 265 )
176 266 else:
177 267 RepoModel().grant_users_group_permission(
178 268 repo=cur_repo, group_name=member, perm=perm
179 269 )
180 270 # set new permissions
181 271 for member, perm, member_type in kwargs['perms_new']:
182 272 if member_type == 'user':
183 273 RepoModel().grant_user_permission(
184 274 repo=cur_repo, user=member, perm=perm
185 275 )
186 276 else:
187 277 RepoModel().grant_users_group_permission(
188 278 repo=cur_repo, group_name=member, perm=perm
189 279 )
190 280
191 281 if 'user' in kwargs:
192 282 cur_repo.user = User.get_by_username(kwargs['user'])
193 283
194 284 if 'repo_group' in kwargs:
195 285 cur_repo.group = RepoGroup.get(kwargs['repo_group'])
196 286
197 287 for strip, k in [(0, 'repo_type'), (1, 'repo_enable_downloads'),
198 288 (1, 'repo_description'), (1, 'repo_enable_locking'),
199 289 (1, 'repo_landing_rev'), (0, 'clone_uri'),
200 290 (1, 'repo_private'), (1, 'repo_enable_statistics')]:
201 291 if k in kwargs:
202 292 val = kwargs[k]
203 293 if strip:
204 294 k = remove_prefix(k, 'repo_')
205 295 setattr(cur_repo, k, val)
206 296
207 297 new_name = cur_repo.get_new_name(kwargs['repo_name'])
208 298 cur_repo.repo_name = new_name
209 299
210 300 self.sa.add(cur_repo)
211 301
212 302 if org_repo_name != new_name:
213 303 # rename repository
214 304 self.__rename_repo(old=org_repo_name, new=new_name)
215 305
216 306 return cur_repo
217 307 except:
218 308 log.error(traceback.format_exc())
219 309 raise
220 310
221 311 def create_repo(self, repo_name, repo_type, description, owner,
222 312 private=False, clone_uri=None, repos_group=None,
223 313 landing_rev='tip', just_db=False, fork_of=None,
224 314 copy_fork_permissions=False, enable_statistics=False,
225 315 enable_locking=False, enable_downloads=False):
226 316 """
227 317 Create repository
228 318
229 319 """
230 320 from rhodecode.model.scm import ScmModel
231 321
232 322 owner = self._get_user(owner)
233 323 fork_of = self._get_repo(fork_of)
234 324 repos_group = self._get_repos_group(repos_group)
235 325 try:
236 326
237 327 # repo name is just a name of repository
238 328 # while repo_name_full is a full qualified name that is combined
239 329 # with name and path of group
240 330 repo_name_full = repo_name
241 331 repo_name = repo_name.split(self.URL_SEPARATOR)[-1]
242 332
243 333 new_repo = Repository()
244 334 new_repo.enable_statistics = False
245 335 new_repo.repo_name = repo_name_full
246 336 new_repo.repo_type = repo_type
247 337 new_repo.user = owner
248 338 new_repo.group = repos_group
249 339 new_repo.description = description or repo_name
250 340 new_repo.private = private
251 341 new_repo.clone_uri = clone_uri
252 342 new_repo.landing_rev = landing_rev
253 343
254 344 new_repo.enable_statistics = enable_statistics
255 345 new_repo.enable_locking = enable_locking
256 346 new_repo.enable_downloads = enable_downloads
257 347
258 348 if repos_group:
259 349 new_repo.enable_locking = repos_group.enable_locking
260 350
261 351 if fork_of:
262 352 parent_repo = fork_of
263 353 new_repo.fork = parent_repo
264 354
265 355 self.sa.add(new_repo)
266 356
267 357 def _create_default_perms():
268 358 # create default permission
269 359 repo_to_perm = UserRepoToPerm()
270 360 default = 'repository.read'
271 361 for p in User.get_by_username('default').user_perms:
272 362 if p.permission.permission_name.startswith('repository.'):
273 363 default = p.permission.permission_name
274 364 break
275 365
276 366 default_perm = 'repository.none' if private else default
277 367
278 368 repo_to_perm.permission_id = self.sa.query(Permission)\
279 369 .filter(Permission.permission_name == default_perm)\
280 370 .one().permission_id
281 371
282 372 repo_to_perm.repository = new_repo
283 373 repo_to_perm.user_id = User.get_by_username('default').user_id
284 374
285 375 self.sa.add(repo_to_perm)
286 376
287 377 if fork_of:
288 378 if copy_fork_permissions:
289 379 repo = fork_of
290 380 user_perms = UserRepoToPerm.query()\
291 381 .filter(UserRepoToPerm.repository == repo).all()
292 382 group_perms = UsersGroupRepoToPerm.query()\
293 383 .filter(UsersGroupRepoToPerm.repository == repo).all()
294 384
295 385 for perm in user_perms:
296 386 UserRepoToPerm.create(perm.user, new_repo,
297 387 perm.permission)
298 388
299 389 for perm in group_perms:
300 390 UsersGroupRepoToPerm.create(perm.users_group, new_repo,
301 391 perm.permission)
302 392 else:
303 393 _create_default_perms()
304 394 else:
305 395 _create_default_perms()
306 396
307 397 if not just_db:
308 398 self.__create_repo(repo_name, repo_type,
309 399 repos_group,
310 400 clone_uri)
311 401 log_create_repository(new_repo.get_dict(),
312 402 created_by=owner.username)
313 403
314 404 # now automatically start following this repository as owner
315 405 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
316 406 owner.user_id)
317 407 return new_repo
318 408 except:
319 409 log.error(traceback.format_exc())
320 410 raise
321 411
322 412 def create(self, form_data, cur_user, just_db=False, fork=None):
323 413 """
324 414 Backward compatibility function, just a wrapper on top of create_repo
325 415
326 416 :param form_data:
327 417 :param cur_user:
328 418 :param just_db:
329 419 :param fork:
330 420 """
331 421 owner = cur_user
332 422 repo_name = form_data['repo_name_full']
333 423 repo_type = form_data['repo_type']
334 424 description = form_data['repo_description']
335 425 private = form_data['repo_private']
336 426 clone_uri = form_data.get('clone_uri')
337 427 repos_group = form_data['repo_group']
338 428 landing_rev = form_data['repo_landing_rev']
339 429 copy_fork_permissions = form_data.get('copy_permissions')
340 430 fork_of = form_data.get('fork_parent_id')
341 431
342 432 ## repo creation defaults, private and repo_type are filled in form
343 433 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
344 434 enable_statistics = defs.get('repo_enable_statistics')
345 435 enable_locking = defs.get('repo_enable_locking')
346 436 enable_downloads = defs.get('repo_enable_downloads')
347 437
348 438 return self.create_repo(
349 439 repo_name, repo_type, description, owner, private, clone_uri,
350 440 repos_group, landing_rev, just_db, fork_of, copy_fork_permissions,
351 441 enable_statistics, enable_locking, enable_downloads
352 442 )
353 443
354 444 def create_fork(self, form_data, cur_user):
355 445 """
356 446 Simple wrapper into executing celery task for fork creation
357 447
358 448 :param form_data:
359 449 :param cur_user:
360 450 """
361 451 from rhodecode.lib.celerylib import tasks, run_task
362 452 run_task(tasks.create_repo_fork, form_data, cur_user)
363 453
364 454 def delete(self, repo):
365 455 repo = self._get_repo(repo)
366 456 if repo:
367 457 old_repo_dict = repo.get_dict()
368 458 owner = repo.user
369 459 try:
370 460 self.sa.delete(repo)
371 461 self.__delete_repo(repo)
372 462 log_delete_repository(old_repo_dict,
373 463 deleted_by=owner.username)
374 464 except:
375 465 log.error(traceback.format_exc())
376 466 raise
377 467
378 468 def grant_user_permission(self, repo, user, perm):
379 469 """
380 470 Grant permission for user on given repository, or update existing one
381 471 if found
382 472
383 473 :param repo: Instance of Repository, repository_id, or repository name
384 474 :param user: Instance of User, user_id or username
385 475 :param perm: Instance of Permission, or permission_name
386 476 """
387 477 user = self._get_user(user)
388 478 repo = self._get_repo(repo)
389 479 permission = self._get_perm(perm)
390 480
391 481 # check if we have that permission already
392 482 obj = self.sa.query(UserRepoToPerm)\
393 483 .filter(UserRepoToPerm.user == user)\
394 484 .filter(UserRepoToPerm.repository == repo)\
395 485 .scalar()
396 486 if obj is None:
397 487 # create new !
398 488 obj = UserRepoToPerm()
399 489 obj.repository = repo
400 490 obj.user = user
401 491 obj.permission = permission
402 492 self.sa.add(obj)
403 493 log.debug('Granted perm %s to %s on %s' % (perm, user, repo))
404 494
405 495 def revoke_user_permission(self, repo, user):
406 496 """
407 497 Revoke permission for user on given repository
408 498
409 499 :param repo: Instance of Repository, repository_id, or repository name
410 500 :param user: Instance of User, user_id or username
411 501 """
412 502
413 503 user = self._get_user(user)
414 504 repo = self._get_repo(repo)
415 505
416 506 obj = self.sa.query(UserRepoToPerm)\
417 507 .filter(UserRepoToPerm.repository == repo)\
418 508 .filter(UserRepoToPerm.user == user)\
419 509 .scalar()
420 510 if obj:
421 511 self.sa.delete(obj)
422 512 log.debug('Revoked perm on %s on %s' % (repo, user))
423 513
424 514 def grant_users_group_permission(self, repo, group_name, perm):
425 515 """
426 516 Grant permission for users group on given repository, or update
427 517 existing one if found
428 518
429 519 :param repo: Instance of Repository, repository_id, or repository name
430 520 :param group_name: Instance of UserGroup, users_group_id,
431 521 or users group name
432 522 :param perm: Instance of Permission, or permission_name
433 523 """
434 524 repo = self._get_repo(repo)
435 525 group_name = self.__get_users_group(group_name)
436 526 permission = self._get_perm(perm)
437 527
438 528 # check if we have that permission already
439 529 obj = self.sa.query(UsersGroupRepoToPerm)\
440 530 .filter(UsersGroupRepoToPerm.users_group == group_name)\
441 531 .filter(UsersGroupRepoToPerm.repository == repo)\
442 532 .scalar()
443 533
444 534 if obj is None:
445 535 # create new
446 536 obj = UsersGroupRepoToPerm()
447 537
448 538 obj.repository = repo
449 539 obj.users_group = group_name
450 540 obj.permission = permission
451 541 self.sa.add(obj)
452 542 log.debug('Granted perm %s to %s on %s' % (perm, group_name, repo))
453 543
454 544 def revoke_users_group_permission(self, repo, group_name):
455 545 """
456 546 Revoke permission for users group on given repository
457 547
458 548 :param repo: Instance of Repository, repository_id, or repository name
459 549 :param group_name: Instance of UserGroup, users_group_id,
460 550 or users group name
461 551 """
462 552 repo = self._get_repo(repo)
463 553 group_name = self.__get_users_group(group_name)
464 554
465 555 obj = self.sa.query(UsersGroupRepoToPerm)\
466 556 .filter(UsersGroupRepoToPerm.repository == repo)\
467 557 .filter(UsersGroupRepoToPerm.users_group == group_name)\
468 558 .scalar()
469 559 if obj:
470 560 self.sa.delete(obj)
471 561 log.debug('Revoked perm to %s on %s' % (repo, group_name))
472 562
473 563 def delete_stats(self, repo_name):
474 564 """
475 565 removes stats for given repo
476 566
477 567 :param repo_name:
478 568 """
479 569 try:
480 570 obj = self.sa.query(Statistics)\
481 571 .filter(Statistics.repository ==
482 572 self.get_by_repo_name(repo_name))\
483 573 .one()
484 574 self.sa.delete(obj)
485 575 except:
486 576 log.error(traceback.format_exc())
487 577 raise
488 578
489 579 def __create_repo(self, repo_name, alias, parent, clone_uri=False):
490 580 """
491 581 makes repository on filesystem. It's group aware means it'll create
492 582 a repository within a group, and alter the paths accordingly of
493 583 group location
494 584
495 585 :param repo_name:
496 586 :param alias:
497 587 :param parent_id:
498 588 :param clone_uri:
499 589 """
500 590 from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
501 591 from rhodecode.model.scm import ScmModel
502 592
503 593 if parent:
504 594 new_parent_path = os.sep.join(parent.full_path_splitted)
505 595 else:
506 596 new_parent_path = ''
507 597
508 598 # we need to make it str for mercurial
509 599 repo_path = os.path.join(*map(lambda x: safe_str(x),
510 600 [self.repos_path, new_parent_path, repo_name]))
511 601
512 602 # check if this path is not a repository
513 603 if is_valid_repo(repo_path, self.repos_path):
514 604 raise Exception('This path %s is a valid repository' % repo_path)
515 605
516 606 # check if this path is a group
517 607 if is_valid_repos_group(repo_path, self.repos_path):
518 608 raise Exception('This path %s is a valid group' % repo_path)
519 609
520 610 log.info('creating repo %s in %s @ %s' % (
521 611 repo_name, safe_unicode(repo_path), clone_uri
522 612 )
523 613 )
524 614 backend = get_backend(alias)
525 615 if alias == 'hg':
526 616 backend(repo_path, create=True, src_url=clone_uri)
527 617 elif alias == 'git':
528 618 r = backend(repo_path, create=True, src_url=clone_uri, bare=True)
529 619 # add rhodecode hook into this repo
530 620 ScmModel().install_git_hook(repo=r)
531 621 else:
532 622 raise Exception('Undefined alias %s' % alias)
533 623
534 624 def __rename_repo(self, old, new):
535 625 """
536 626 renames repository on filesystem
537 627
538 628 :param old: old name
539 629 :param new: new name
540 630 """
541 631 log.info('renaming repo from %s to %s' % (old, new))
542 632
543 633 old_path = os.path.join(self.repos_path, old)
544 634 new_path = os.path.join(self.repos_path, new)
545 635 if os.path.isdir(new_path):
546 636 raise Exception(
547 637 'Was trying to rename to already existing dir %s' % new_path
548 638 )
549 639 shutil.move(old_path, new_path)
550 640
551 641 def __delete_repo(self, repo):
552 642 """
553 643 removes repo from filesystem, the removal is acctually made by
554 644 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
555 645 repository is no longer valid for rhodecode, can be undeleted later on
556 646 by reverting the renames on this repository
557 647
558 648 :param repo: repo object
559 649 """
560 650 rm_path = os.path.join(self.repos_path, repo.repo_name)
561 651 log.info("Removing %s" % (rm_path))
562 652 # disable hg/git internal that it doesn't get detected as repo
563 653 alias = repo.repo_type
564 654
565 655 bare = getattr(repo.scm_instance, 'bare', False)
566 656
567 657 if not bare:
568 658 # skip this for bare git repos
569 659 shutil.move(os.path.join(rm_path, '.%s' % alias),
570 660 os.path.join(rm_path, 'rm__.%s' % alias))
571 661 # disable repo
572 662 _now = datetime.now()
573 663 _ms = str(_now.microsecond).rjust(6, '0')
574 664 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
575 665 repo.just_name)
576 666 if repo.group:
577 667 args = repo.group.full_path_splitted + [_d]
578 668 _d = os.path.join(*args)
579 669 shutil.move(rm_path, os.path.join(self.repos_path, _d))
@@ -1,4847 +1,4847 b''
1 1 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td
2 2 {
3 3 border: 0;
4 4 outline: 0;
5 5 font-size: 100%;
6 6 vertical-align: baseline;
7 7 background: transparent;
8 8 margin: 0;
9 9 padding: 0;
10 10 }
11 11
12 12 body {
13 13 line-height: 1;
14 14 height: 100%;
15 15 background: url("../images/background.png") repeat scroll 0 0 #B0B0B0;
16 16 font-family: Lucida Grande, Verdana, Lucida Sans Regular,
17 17 Lucida Sans Unicode, Arial, sans-serif; font-size : 12px;
18 18 color: #000;
19 19 margin: 0;
20 20 padding: 0;
21 21 font-size: 12px;
22 22 }
23 23
24 24 ol,ul {
25 25 list-style: none;
26 26 }
27 27
28 28 blockquote,q {
29 29 quotes: none;
30 30 }
31 31
32 32 blockquote:before,blockquote:after,q:before,q:after {
33 33 content: none;
34 34 }
35 35
36 36 :focus {
37 37 outline: 0;
38 38 }
39 39
40 40 del {
41 41 text-decoration: line-through;
42 42 }
43 43
44 44 table {
45 45 border-collapse: collapse;
46 46 border-spacing: 0;
47 47 }
48 48
49 49 html {
50 50 height: 100%;
51 51 }
52 52
53 53 a {
54 54 color: #003367;
55 55 text-decoration: none;
56 56 cursor: pointer;
57 57 }
58 58
59 59 a:hover {
60 60 color: #316293;
61 61 text-decoration: underline;
62 62 }
63 63
64 64 h1,h2,h3,h4,h5,h6,
65 65 div.h1,div.h2,div.h3,div.h4,div.h5,div.h6 {
66 66 color: #292929;
67 67 font-weight: 700;
68 68 }
69 69
70 70 h1,div.h1 {
71 71 font-size: 22px;
72 72 }
73 73
74 74 h2,div.h2 {
75 75 font-size: 20px;
76 76 }
77 77
78 78 h3,div.h3 {
79 79 font-size: 18px;
80 80 }
81 81
82 82 h4,div.h4 {
83 83 font-size: 16px;
84 84 }
85 85
86 86 h5,div.h5 {
87 87 font-size: 14px;
88 88 }
89 89
90 90 h6,div.h6 {
91 91 font-size: 11px;
92 92 }
93 93
94 94 ul.circle {
95 95 list-style-type: circle;
96 96 }
97 97
98 98 ul.disc {
99 99 list-style-type: disc;
100 100 }
101 101
102 102 ul.square {
103 103 list-style-type: square;
104 104 }
105 105
106 106 ol.lower-roman {
107 107 list-style-type: lower-roman;
108 108 }
109 109
110 110 ol.upper-roman {
111 111 list-style-type: upper-roman;
112 112 }
113 113
114 114 ol.lower-alpha {
115 115 list-style-type: lower-alpha;
116 116 }
117 117
118 118 ol.upper-alpha {
119 119 list-style-type: upper-alpha;
120 120 }
121 121
122 122 ol.decimal {
123 123 list-style-type: decimal;
124 124 }
125 125
126 126 div.color {
127 127 clear: both;
128 128 overflow: hidden;
129 129 position: absolute;
130 130 background: #FFF;
131 131 margin: 7px 0 0 60px;
132 132 padding: 1px 1px 1px 0;
133 133 }
134 134
135 135 div.color a {
136 136 width: 15px;
137 137 height: 15px;
138 138 display: block;
139 139 float: left;
140 140 margin: 0 0 0 1px;
141 141 padding: 0;
142 142 }
143 143
144 144 div.options {
145 145 clear: both;
146 146 overflow: hidden;
147 147 position: absolute;
148 148 background: #FFF;
149 149 margin: 7px 0 0 162px;
150 150 padding: 0;
151 151 }
152 152
153 153 div.options a {
154 154 height: 1%;
155 155 display: block;
156 156 text-decoration: none;
157 157 margin: 0;
158 158 padding: 3px 8px;
159 159 }
160 160
161 161 .top-left-rounded-corner {
162 162 -webkit-border-top-left-radius: 8px;
163 163 -khtml-border-radius-topleft: 8px;
164 164 -moz-border-radius-topleft: 8px;
165 165 border-top-left-radius: 8px;
166 166 }
167 167
168 168 .top-right-rounded-corner {
169 169 -webkit-border-top-right-radius: 8px;
170 170 -khtml-border-radius-topright: 8px;
171 171 -moz-border-radius-topright: 8px;
172 172 border-top-right-radius: 8px;
173 173 }
174 174
175 175 .bottom-left-rounded-corner {
176 176 -webkit-border-bottom-left-radius: 8px;
177 177 -khtml-border-radius-bottomleft: 8px;
178 178 -moz-border-radius-bottomleft: 8px;
179 179 border-bottom-left-radius: 8px;
180 180 }
181 181
182 182 .bottom-right-rounded-corner {
183 183 -webkit-border-bottom-right-radius: 8px;
184 184 -khtml-border-radius-bottomright: 8px;
185 185 -moz-border-radius-bottomright: 8px;
186 186 border-bottom-right-radius: 8px;
187 187 }
188 188
189 189 .top-left-rounded-corner-mid {
190 190 -webkit-border-top-left-radius: 4px;
191 191 -khtml-border-radius-topleft: 4px;
192 192 -moz-border-radius-topleft: 4px;
193 193 border-top-left-radius: 4px;
194 194 }
195 195
196 196 .top-right-rounded-corner-mid {
197 197 -webkit-border-top-right-radius: 4px;
198 198 -khtml-border-radius-topright: 4px;
199 199 -moz-border-radius-topright: 4px;
200 200 border-top-right-radius: 4px;
201 201 }
202 202
203 203 .bottom-left-rounded-corner-mid {
204 204 -webkit-border-bottom-left-radius: 4px;
205 205 -khtml-border-radius-bottomleft: 4px;
206 206 -moz-border-radius-bottomleft: 4px;
207 207 border-bottom-left-radius: 4px;
208 208 }
209 209
210 210 .bottom-right-rounded-corner-mid {
211 211 -webkit-border-bottom-right-radius: 4px;
212 212 -khtml-border-radius-bottomright: 4px;
213 213 -moz-border-radius-bottomright: 4px;
214 214 border-bottom-right-radius: 4px;
215 215 }
216 216
217 217 .help-block {
218 218 color: #999999;
219 219 display: block;
220 220 margin-bottom: 0;
221 221 margin-top: 5px;
222 222 }
223 223
224 224 .empty_data{
225 225 color:#B9B9B9;
226 226 }
227 227
228 228 a.permalink{
229 229 visibility: hidden;
230 230 }
231 231
232 232 a.permalink:hover{
233 233 text-decoration: none;
234 234 }
235 235
236 236 h1:hover > a.permalink,
237 237 h2:hover > a.permalink,
238 238 h3:hover > a.permalink,
239 239 h4:hover > a.permalink,
240 240 h5:hover > a.permalink,
241 241 h6:hover > a.permalink,
242 242 div:hover > a.permalink {
243 243 visibility: visible;
244 244 }
245 245
246 246 #header {
247 247 margin: 0;
248 248 padding: 0 10px;
249 249 }
250 250
251 251 #header ul#logged-user {
252 252 margin-bottom: 5px !important;
253 253 -webkit-border-radius: 0px 0px 8px 8px;
254 254 -khtml-border-radius: 0px 0px 8px 8px;
255 255 -moz-border-radius: 0px 0px 8px 8px;
256 256 border-radius: 0px 0px 8px 8px;
257 257 height: 37px;
258 258 background-color: #003B76;
259 259 background-repeat: repeat-x;
260 260 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
261 261 background-image: -moz-linear-gradient(top, #003b76, #00376e);
262 262 background-image: -ms-linear-gradient(top, #003b76, #00376e);
263 263 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
264 264 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
265 265 background-image: -o-linear-gradient(top, #003b76, #00376e);
266 266 background-image: linear-gradient(top, #003b76, #00376e);
267 267 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
268 268 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
269 269 }
270 270
271 271 #header ul#logged-user li {
272 272 list-style: none;
273 273 float: left;
274 274 margin: 8px 0 0;
275 275 padding: 4px 12px;
276 276 border-left: 1px solid #316293;
277 277 }
278 278
279 279 #header ul#logged-user li.first {
280 280 border-left: none;
281 281 margin: 4px;
282 282 }
283 283
284 284 #header ul#logged-user li.first div.gravatar {
285 285 margin-top: -2px;
286 286 }
287 287
288 288 #header ul#logged-user li.first div.account {
289 289 padding-top: 4px;
290 290 float: left;
291 291 }
292 292
293 293 #header ul#logged-user li.last {
294 294 border-right: none;
295 295 }
296 296
297 297 #header ul#logged-user li a {
298 298 color: #fff;
299 299 font-weight: 700;
300 300 text-decoration: none;
301 301 }
302 302
303 303 #header ul#logged-user li a:hover {
304 304 text-decoration: underline;
305 305 }
306 306
307 307 #header ul#logged-user li.highlight a {
308 308 color: #fff;
309 309 }
310 310
311 311 #header ul#logged-user li.highlight a:hover {
312 312 color: #FFF;
313 313 }
314 314
315 315 #header #header-inner {
316 316 min-height: 44px;
317 317 clear: both;
318 318 position: relative;
319 319 background-color: #003B76;
320 320 background-repeat: repeat-x;
321 321 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
322 322 background-image: -moz-linear-gradient(top, #003b76, #00376e);
323 323 background-image: -ms-linear-gradient(top, #003b76, #00376e);
324 324 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76),color-stop(100%, #00376e) );
325 325 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
326 326 background-image: -o-linear-gradient(top, #003b76, #00376e);
327 327 background-image: linear-gradient(top, #003b76, #00376e);
328 328 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
329 329 margin: 0;
330 330 padding: 0;
331 331 display: block;
332 332 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
333 333 -webkit-border-radius: 4px 4px 4px 4px;
334 334 -khtml-border-radius: 4px 4px 4px 4px;
335 335 -moz-border-radius: 4px 4px 4px 4px;
336 336 border-radius: 4px 4px 4px 4px;
337 337 }
338 338 #header #header-inner.hover{
339 339 position: fixed !important;
340 340 width: 100% !important;
341 341 margin-left: -10px !important;
342 342 z-index: 10000;
343 343 -webkit-border-radius: 0px 0px 0px 0px;
344 344 -khtml-border-radius: 0px 0px 0px 0px;
345 345 -moz-border-radius: 0px 0px 0px 0px;
346 346 border-radius: 0px 0px 0px 0px;
347 347 }
348 348
349 349 .ie7 #header #header-inner.hover,
350 350 .ie8 #header #header-inner.hover,
351 351 .ie9 #header #header-inner.hover
352 352 {
353 353 z-index: auto !important;
354 354 }
355 355
356 356 .header-pos-fix, .anchor{
357 357 margin-top: -46px;
358 358 padding-top: 46px;
359 359 }
360 360
361 361 #header #header-inner #home a {
362 362 height: 40px;
363 363 width: 46px;
364 364 display: block;
365 365 background: url("../images/button_home.png");
366 366 background-position: 0 0;
367 367 margin: 0;
368 368 padding: 0;
369 369 }
370 370
371 371 #header #header-inner #home a:hover {
372 372 background-position: 0 -40px;
373 373 }
374 374
375 375 #header #header-inner #logo {
376 376 float: left;
377 377 position: absolute;
378 378 }
379 379
380 380 #header #header-inner #logo h1 {
381 381 color: #FFF;
382 382 font-size: 20px;
383 383 margin: 12px 0 0 13px;
384 384 padding: 0;
385 385 }
386 386
387 387 #header #header-inner #logo a {
388 388 color: #fff;
389 389 text-decoration: none;
390 390 }
391 391
392 392 #header #header-inner #logo a:hover {
393 393 color: #bfe3ff;
394 394 }
395 395
396 396 #header #header-inner #quick,#header #header-inner #quick ul {
397 397 position: relative;
398 398 float: right;
399 399 list-style-type: none;
400 400 list-style-position: outside;
401 401 margin: 8px 8px 0 0;
402 402 padding: 0;
403 403 }
404 404
405 405 #header #header-inner #quick li {
406 406 position: relative;
407 407 float: left;
408 408 margin: 0 5px 0 0;
409 409 padding: 0;
410 410 }
411 411
412 412 #header #header-inner #quick li a.menu_link {
413 413 top: 0;
414 414 left: 0;
415 415 height: 1%;
416 416 display: block;
417 417 clear: both;
418 418 overflow: hidden;
419 419 color: #FFF;
420 420 font-weight: 700;
421 421 text-decoration: none;
422 422 background: #369;
423 423 padding: 0;
424 424 -webkit-border-radius: 4px 4px 4px 4px;
425 425 -khtml-border-radius: 4px 4px 4px 4px;
426 426 -moz-border-radius: 4px 4px 4px 4px;
427 427 border-radius: 4px 4px 4px 4px;
428 428 }
429 429
430 430 #header #header-inner #quick li span.short {
431 431 padding: 9px 6px 8px 6px;
432 432 }
433 433
434 434 #header #header-inner #quick li span {
435 435 top: 0;
436 436 right: 0;
437 437 height: 1%;
438 438 display: block;
439 439 float: left;
440 440 border-left: 1px solid #3f6f9f;
441 441 margin: 0;
442 442 padding: 10px 12px 8px 10px;
443 443 }
444 444
445 445 #header #header-inner #quick li span.normal {
446 446 border: none;
447 447 padding: 10px 12px 8px;
448 448 }
449 449
450 450 #header #header-inner #quick li span.icon {
451 451 top: 0;
452 452 left: 0;
453 453 border-left: none;
454 454 border-right: 1px solid #2e5c89;
455 455 padding: 8px 6px 4px;
456 456 }
457 457
458 458 #header #header-inner #quick li span.icon_short {
459 459 top: 0;
460 460 left: 0;
461 461 border-left: none;
462 462 border-right: 1px solid #2e5c89;
463 463 padding: 8px 6px 4px;
464 464 }
465 465
466 466 #header #header-inner #quick li span.icon img,#header #header-inner #quick li span.icon_short img
467 467 {
468 468 margin: 0px -2px 0px 0px;
469 469 }
470 470
471 471 #header #header-inner #quick li a:hover {
472 472 background: #4e4e4e no-repeat top left;
473 473 }
474 474
475 475 #header #header-inner #quick li a:hover span {
476 476 border-left: 1px solid #545454;
477 477 }
478 478
479 479 #header #header-inner #quick li a:hover span.icon,#header #header-inner #quick li a:hover span.icon_short
480 480 {
481 481 border-left: none;
482 482 border-right: 1px solid #464646;
483 483 }
484 484
485 485 #header #header-inner #quick ul {
486 486 top: 29px;
487 487 right: 0;
488 488 min-width: 200px;
489 489 display: none;
490 490 position: absolute;
491 491 background: #FFF;
492 492 border: 1px solid #666;
493 493 border-top: 1px solid #003367;
494 494 z-index: 100;
495 495 margin: 0px 0px 0px 0px;
496 496 padding: 0;
497 497 }
498 498
499 499 #header #header-inner #quick ul.repo_switcher {
500 500 max-height: 275px;
501 501 overflow-x: hidden;
502 502 overflow-y: auto;
503 503 }
504 504
505 505 #header #header-inner #quick ul.repo_switcher li.qfilter_rs {
506 506 float: none;
507 507 margin: 0;
508 508 border-bottom: 2px solid #003367;
509 509 }
510 510
511 511 #header #header-inner #quick .repo_switcher_type {
512 512 position: absolute;
513 513 left: 0;
514 514 top: 9px;
515 515 }
516 516
517 517 #header #header-inner #quick li ul li {
518 518 border-bottom: 1px solid #ddd;
519 519 }
520 520
521 521 #header #header-inner #quick li ul li a {
522 522 width: 182px;
523 523 height: auto;
524 524 display: block;
525 525 float: left;
526 526 background: #FFF;
527 527 color: #003367;
528 528 font-weight: 400;
529 529 margin: 0;
530 530 padding: 7px 9px;
531 531 }
532 532
533 533 #header #header-inner #quick li ul li a:hover {
534 534 color: #000;
535 535 background: #FFF;
536 536 }
537 537
538 538 #header #header-inner #quick ul ul {
539 539 top: auto;
540 540 }
541 541
542 542 #header #header-inner #quick li ul ul {
543 543 right: 200px;
544 544 max-height: 290px;
545 545 overflow: auto;
546 546 overflow-x: hidden;
547 547 white-space: normal;
548 548 }
549 549
550 550 #header #header-inner #quick li ul li a.journal,#header #header-inner #quick li ul li a.journal:hover
551 551 {
552 552 background: url("../images/icons/book.png") no-repeat scroll 4px 9px
553 553 #FFF;
554 554 width: 167px;
555 555 margin: 0;
556 556 padding: 12px 9px 7px 24px;
557 557 }
558 558
559 559 #header #header-inner #quick li ul li a.private_repo,#header #header-inner #quick li ul li a.private_repo:hover
560 560 {
561 561 background: url("../images/icons/lock.png") no-repeat scroll 4px 9px
562 562 #FFF;
563 563 min-width: 167px;
564 564 margin: 0;
565 565 padding: 12px 9px 7px 24px;
566 566 }
567 567
568 568 #header #header-inner #quick li ul li a.public_repo,#header #header-inner #quick li ul li a.public_repo:hover
569 569 {
570 570 background: url("../images/icons/lock_open.png") no-repeat scroll 4px
571 571 9px #FFF;
572 572 min-width: 167px;
573 573 margin: 0;
574 574 padding: 12px 9px 7px 24px;
575 575 }
576 576
577 577 #header #header-inner #quick li ul li a.hg,#header #header-inner #quick li ul li a.hg:hover
578 578 {
579 579 background: url("../images/icons/hgicon.png") no-repeat scroll 4px 9px
580 580 #FFF;
581 581 min-width: 167px;
582 582 margin: 0 0 0 14px;
583 583 padding: 12px 9px 7px 24px;
584 584 }
585 585
586 586 #header #header-inner #quick li ul li a.git,#header #header-inner #quick li ul li a.git:hover
587 587 {
588 588 background: url("../images/icons/giticon.png") no-repeat scroll 4px 9px
589 589 #FFF;
590 590 min-width: 167px;
591 591 margin: 0 0 0 14px;
592 592 padding: 12px 9px 7px 24px;
593 593 }
594 594
595 595 #header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover
596 596 {
597 597 background: url("../images/icons/database_edit.png") no-repeat scroll
598 598 4px 9px #FFF;
599 599 width: 167px;
600 600 margin: 0;
601 601 padding: 12px 9px 7px 24px;
602 602 }
603 603
604 604 #header #header-inner #quick li ul li a.repos_groups,#header #header-inner #quick li ul li a.repos_groups:hover
605 605 {
606 606 background: url("../images/icons/database_link.png") no-repeat scroll
607 607 4px 9px #FFF;
608 608 width: 167px;
609 609 margin: 0;
610 610 padding: 12px 9px 7px 24px;
611 611 }
612 612
613 613 #header #header-inner #quick li ul li a.users,#header #header-inner #quick li ul li a.users:hover
614 614 {
615 615 background: #FFF url("../images/icons/user_edit.png") no-repeat 4px 9px;
616 616 width: 167px;
617 617 margin: 0;
618 618 padding: 12px 9px 7px 24px;
619 619 }
620 620
621 621 #header #header-inner #quick li ul li a.groups,#header #header-inner #quick li ul li a.groups:hover
622 622 {
623 623 background: #FFF url("../images/icons/group_edit.png") no-repeat 4px 9px;
624 624 width: 167px;
625 625 margin: 0;
626 626 padding: 12px 9px 7px 24px;
627 627 }
628 628
629 629 #header #header-inner #quick li ul li a.defaults,#header #header-inner #quick li ul li a.defaults:hover
630 630 {
631 631 background: #FFF url("../images/icons/wrench.png") no-repeat 4px 9px;
632 632 width: 167px;
633 633 margin: 0;
634 634 padding: 12px 9px 7px 24px;
635 635 }
636 636
637 637 #header #header-inner #quick li ul li a.settings,#header #header-inner #quick li ul li a.settings:hover
638 638 {
639 639 background: #FFF url("../images/icons/cog.png") no-repeat 4px 9px;
640 640 width: 167px;
641 641 margin: 0;
642 642 padding: 12px 9px 7px 24px;
643 643 }
644 644
645 645 #header #header-inner #quick li ul li a.permissions,#header #header-inner #quick li ul li a.permissions:hover
646 646 {
647 647 background: #FFF url("../images/icons/key.png") no-repeat 4px 9px;
648 648 width: 167px;
649 649 margin: 0;
650 650 padding: 12px 9px 7px 24px;
651 651 }
652 652
653 653 #header #header-inner #quick li ul li a.ldap,#header #header-inner #quick li ul li a.ldap:hover
654 654 {
655 655 background: #FFF url("../images/icons/server_key.png") no-repeat 4px 9px;
656 656 width: 167px;
657 657 margin: 0;
658 658 padding: 12px 9px 7px 24px;
659 659 }
660 660
661 661 #header #header-inner #quick li ul li a.fork,#header #header-inner #quick li ul li a.fork:hover
662 662 {
663 663 background: #FFF url("../images/icons/arrow_divide.png") no-repeat 4px
664 664 9px;
665 665 width: 167px;
666 666 margin: 0;
667 667 padding: 12px 9px 7px 24px;
668 668 }
669 669
670 670 #header #header-inner #quick li ul li a.locking_add,#header #header-inner #quick li ul li a.locking_add:hover
671 671 {
672 672 background: #FFF url("../images/icons/lock_add.png") no-repeat 4px
673 673 9px;
674 674 width: 167px;
675 675 margin: 0;
676 676 padding: 12px 9px 7px 24px;
677 677 }
678 678
679 679 #header #header-inner #quick li ul li a.locking_del,#header #header-inner #quick li ul li a.locking_del:hover
680 680 {
681 681 background: #FFF url("../images/icons/lock_delete.png") no-repeat 4px
682 682 9px;
683 683 width: 167px;
684 684 margin: 0;
685 685 padding: 12px 9px 7px 24px;
686 686 }
687 687
688 688 #header #header-inner #quick li ul li a.pull_request,#header #header-inner #quick li ul li a.pull_request:hover
689 689 {
690 690 background: #FFF url("../images/icons/arrow_join.png") no-repeat 4px
691 691 9px;
692 692 width: 167px;
693 693 margin: 0;
694 694 padding: 12px 9px 7px 24px;
695 695 }
696 696
697 697 #header #header-inner #quick li ul li a.compare_request,#header #header-inner #quick li ul li a.compare_request:hover
698 698 {
699 699 background: #FFF url("../images/icons/arrow_inout.png") no-repeat 4px
700 700 9px;
701 701 width: 167px;
702 702 margin: 0;
703 703 padding: 12px 9px 7px 24px;
704 704 }
705 705
706 706 #header #header-inner #quick li ul li a.search,#header #header-inner #quick li ul li a.search:hover
707 707 {
708 708 background: #FFF url("../images/icons/search_16.png") no-repeat 4px 9px;
709 709 width: 167px;
710 710 margin: 0;
711 711 padding: 12px 9px 7px 24px;
712 712 }
713 713
714 714 #header #header-inner #quick li ul li a.delete,#header #header-inner #quick li ul li a.delete:hover
715 715 {
716 716 background: #FFF url("../images/icons/delete.png") no-repeat 4px 9px;
717 717 width: 167px;
718 718 margin: 0;
719 719 padding: 12px 9px 7px 24px;
720 720 }
721 721
722 722 #header #header-inner #quick li ul li a.branches,#header #header-inner #quick li ul li a.branches:hover
723 723 {
724 724 background: #FFF url("../images/icons/arrow_branch.png") no-repeat 4px
725 725 9px;
726 726 width: 167px;
727 727 margin: 0;
728 728 padding: 12px 9px 7px 24px;
729 729 }
730 730
731 731 #header #header-inner #quick li ul li a.tags,
732 732 #header #header-inner #quick li ul li a.tags:hover{
733 733 background: #FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
734 734 width: 167px;
735 735 margin: 0;
736 736 padding: 12px 9px 7px 24px;
737 737 }
738 738
739 739 #header #header-inner #quick li ul li a.bookmarks,
740 740 #header #header-inner #quick li ul li a.bookmarks:hover{
741 741 background: #FFF url("../images/icons/tag_green.png") no-repeat 4px 9px;
742 742 width: 167px;
743 743 margin: 0;
744 744 padding: 12px 9px 7px 24px;
745 745 }
746 746
747 747 #header #header-inner #quick li ul li a.admin,
748 748 #header #header-inner #quick li ul li a.admin:hover{
749 749 background: #FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
750 750 width: 167px;
751 751 margin: 0;
752 752 padding: 12px 9px 7px 24px;
753 753 }
754 754
755 755 .groups_breadcrumbs a {
756 756 color: #fff;
757 757 }
758 758
759 759 .groups_breadcrumbs a:hover {
760 760 color: #bfe3ff;
761 761 text-decoration: none;
762 762 }
763 763
764 764 td.quick_repo_menu {
765 765 background: #FFF url("../images/vertical-indicator.png") 8px 50% no-repeat !important;
766 766 cursor: pointer;
767 767 width: 8px;
768 768 border: 1px solid transparent;
769 769 }
770 770
771 771 td.quick_repo_menu.active {
772 772 background: url("../images/dt-arrow-dn.png") no-repeat scroll 5px 50% #FFFFFF !important;
773 773 border: 1px solid #003367;
774 774 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
775 775 cursor: pointer;
776 776 }
777 777
778 778 td.quick_repo_menu .menu_items {
779 779 margin-top: 10px;
780 780 margin-left:-6px;
781 781 width: 150px;
782 782 position: absolute;
783 783 background-color: #FFF;
784 784 background: none repeat scroll 0 0 #FFFFFF;
785 785 border-color: #003367 #666666 #666666;
786 786 border-right: 1px solid #666666;
787 787 border-style: solid;
788 788 border-width: 1px;
789 789 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
790 790 border-top-style: none;
791 791 }
792 792
793 793 td.quick_repo_menu .menu_items li {
794 794 padding: 0 !important;
795 795 }
796 796
797 797 td.quick_repo_menu .menu_items a {
798 798 display: block;
799 799 padding: 4px 12px 4px 8px;
800 800 }
801 801
802 802 td.quick_repo_menu .menu_items a:hover {
803 803 background-color: #EEE;
804 804 text-decoration: none;
805 805 }
806 806
807 807 td.quick_repo_menu .menu_items .icon img {
808 808 margin-bottom: -2px;
809 809 }
810 810
811 811 td.quick_repo_menu .menu_items.hidden {
812 812 display: none;
813 813 }
814 814
815 815 .yui-dt-first th {
816 816 text-align: left;
817 817 }
818 818
819 819 /*
820 820 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
821 821 Code licensed under the BSD License:
822 822 http://developer.yahoo.com/yui/license.html
823 823 version: 2.9.0
824 824 */
825 825 .yui-skin-sam .yui-dt-mask {
826 826 position: absolute;
827 827 z-index: 9500;
828 828 }
829 829 .yui-dt-tmp {
830 830 position: absolute;
831 831 left: -9000px;
832 832 }
833 833 .yui-dt-scrollable .yui-dt-bd { overflow: auto }
834 834 .yui-dt-scrollable .yui-dt-hd {
835 835 overflow: hidden;
836 836 position: relative;
837 837 }
838 838 .yui-dt-scrollable .yui-dt-bd thead tr,
839 839 .yui-dt-scrollable .yui-dt-bd thead th {
840 840 position: absolute;
841 841 left: -1500px;
842 842 }
843 843 .yui-dt-scrollable tbody { -moz-outline: 0 }
844 844 .yui-skin-sam thead .yui-dt-sortable { cursor: pointer }
845 845 .yui-skin-sam thead .yui-dt-draggable { cursor: move }
846 846 .yui-dt-coltarget {
847 847 position: absolute;
848 848 z-index: 999;
849 849 }
850 850 .yui-dt-hd { zoom: 1 }
851 851 th.yui-dt-resizeable .yui-dt-resizerliner { position: relative }
852 852 .yui-dt-resizer {
853 853 position: absolute;
854 854 right: 0;
855 855 bottom: 0;
856 856 height: 100%;
857 857 cursor: e-resize;
858 858 cursor: col-resize;
859 859 background-color: #CCC;
860 860 opacity: 0;
861 861 filter: alpha(opacity=0);
862 862 }
863 863 .yui-dt-resizerproxy {
864 864 visibility: hidden;
865 865 position: absolute;
866 866 z-index: 9000;
867 867 background-color: #CCC;
868 868 opacity: 0;
869 869 filter: alpha(opacity=0);
870 870 }
871 871 th.yui-dt-hidden .yui-dt-liner,
872 872 td.yui-dt-hidden .yui-dt-liner,
873 873 th.yui-dt-hidden .yui-dt-resizer { display: none }
874 874 .yui-dt-editor,
875 875 .yui-dt-editor-shim {
876 876 position: absolute;
877 877 z-index: 9000;
878 878 }
879 879 .yui-skin-sam .yui-dt table {
880 880 margin: 0;
881 881 padding: 0;
882 882 font-family: arial;
883 883 font-size: inherit;
884 884 border-collapse: separate;
885 885 *border-collapse: collapse;
886 886 border-spacing: 0;
887 887 border: 1px solid #7f7f7f;
888 888 }
889 889 .yui-skin-sam .yui-dt thead { border-spacing: 0 }
890 890 .yui-skin-sam .yui-dt caption {
891 891 color: #000;
892 892 font-size: 85%;
893 893 font-weight: normal;
894 894 font-style: italic;
895 895 line-height: 1;
896 896 padding: 1em 0;
897 897 text-align: center;
898 898 }
899 899 .yui-skin-sam .yui-dt th { background: #d8d8da url(../images/sprite.png) repeat-x 0 0 }
900 900 .yui-skin-sam .yui-dt th,
901 901 .yui-skin-sam .yui-dt th a {
902 902 font-weight: normal;
903 903 text-decoration: none;
904 904 color: #000;
905 905 vertical-align: bottom;
906 906 }
907 907 .yui-skin-sam .yui-dt th {
908 908 margin: 0;
909 909 padding: 0;
910 910 border: 0;
911 911 border-right: 1px solid #cbcbcb;
912 912 }
913 913 .yui-skin-sam .yui-dt tr.yui-dt-first td { border-top: 1px solid #7f7f7f }
914 914 .yui-skin-sam .yui-dt th .yui-dt-liner { white-space: nowrap }
915 915 .yui-skin-sam .yui-dt-liner {
916 916 margin: 0;
917 917 padding: 0;
918 918 }
919 919 .yui-skin-sam .yui-dt-coltarget {
920 920 width: 5px;
921 921 background-color: red;
922 922 }
923 923 .yui-skin-sam .yui-dt td {
924 924 margin: 0;
925 925 padding: 0;
926 926 border: 0;
927 927 border-right: 1px solid #cbcbcb;
928 928 text-align: left;
929 929 }
930 930 .yui-skin-sam .yui-dt-list td { border-right: 0 }
931 931 .yui-skin-sam .yui-dt-resizer { width: 6px }
932 932 .yui-skin-sam .yui-dt-mask {
933 933 background-color: #000;
934 934 opacity: .25;
935 935 filter: alpha(opacity=25);
936 936 }
937 937 .yui-skin-sam .yui-dt-message { background-color: #FFF }
938 938 .yui-skin-sam .yui-dt-scrollable table { border: 0 }
939 939 .yui-skin-sam .yui-dt-scrollable .yui-dt-hd {
940 940 border-left: 1px solid #7f7f7f;
941 941 border-top: 1px solid #7f7f7f;
942 942 border-right: 1px solid #7f7f7f;
943 943 }
944 944 .yui-skin-sam .yui-dt-scrollable .yui-dt-bd {
945 945 border-left: 1px solid #7f7f7f;
946 946 border-bottom: 1px solid #7f7f7f;
947 947 border-right: 1px solid #7f7f7f;
948 948 background-color: #FFF;
949 949 }
950 950 .yui-skin-sam .yui-dt-scrollable .yui-dt-data tr.yui-dt-last td { border-bottom: 1px solid #7f7f7f }
951 951 .yui-skin-sam th.yui-dt-asc,
952 952 .yui-skin-sam th.yui-dt-desc { background: url(../images/sprite.png) repeat-x 0 -100px }
953 953 .yui-skin-sam th.yui-dt-sortable .yui-dt-label { margin-right: 10px }
954 954 .yui-skin-sam th.yui-dt-asc .yui-dt-liner { background: url(../images/dt-arrow-up.png) no-repeat right }
955 955 .yui-skin-sam th.yui-dt-desc .yui-dt-liner { background: url(../images/dt-arrow-dn.png) no-repeat right }
956 956 tbody .yui-dt-editable { cursor: pointer }
957 957 .yui-dt-editor {
958 958 text-align: left;
959 959 background-color: #f2f2f2;
960 960 border: 1px solid #808080;
961 961 padding: 6px;
962 962 }
963 963 .yui-dt-editor label {
964 964 padding-left: 4px;
965 965 padding-right: 6px;
966 966 }
967 967 .yui-dt-editor .yui-dt-button {
968 968 padding-top: 6px;
969 969 text-align: right;
970 970 }
971 971 .yui-dt-editor .yui-dt-button button {
972 972 background: url(../images/sprite.png) repeat-x 0 0;
973 973 border: 1px solid #999;
974 974 width: 4em;
975 975 height: 1.8em;
976 976 margin-left: 6px;
977 977 }
978 978 .yui-dt-editor .yui-dt-button button.yui-dt-default {
979 979 background: url(../images/sprite.png) repeat-x 0 -1400px;
980 980 background-color: #5584e0;
981 981 border: 1px solid #304369;
982 982 color: #FFF;
983 983 }
984 984 .yui-dt-editor .yui-dt-button button:hover {
985 985 background: url(../images/sprite.png) repeat-x 0 -1300px;
986 986 color: #000;
987 987 }
988 988 .yui-dt-editor .yui-dt-button button:active {
989 989 background: url(../images/sprite.png) repeat-x 0 -1700px;
990 990 color: #000;
991 991 }
992 992 .yui-skin-sam tr.yui-dt-even { background-color: #FFF }
993 993 .yui-skin-sam tr.yui-dt-odd { background-color: #edf5ff }
994 994 .yui-skin-sam tr.yui-dt-even td.yui-dt-asc,
995 995 .yui-skin-sam tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
996 996 .yui-skin-sam tr.yui-dt-odd td.yui-dt-asc,
997 997 .yui-skin-sam tr.yui-dt-odd td.yui-dt-desc { background-color: #dbeaff }
998 998 .yui-skin-sam .yui-dt-list tr.yui-dt-even { background-color: #FFF }
999 999 .yui-skin-sam .yui-dt-list tr.yui-dt-odd { background-color: #FFF }
1000 1000 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-asc,
1001 1001 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
1002 1002 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-asc,
1003 1003 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-desc { background-color: #edf5ff }
1004 1004 .yui-skin-sam th.yui-dt-highlighted,
1005 1005 .yui-skin-sam th.yui-dt-highlighted a { background-color: #b2d2ff }
1006 1006 .yui-skin-sam tr.yui-dt-highlighted,
1007 1007 .yui-skin-sam tr.yui-dt-highlighted td.yui-dt-asc,
1008 1008 .yui-skin-sam tr.yui-dt-highlighted td.yui-dt-desc,
1009 1009 .yui-skin-sam tr.yui-dt-even td.yui-dt-highlighted,
1010 1010 .yui-skin-sam tr.yui-dt-odd td.yui-dt-highlighted {
1011 1011 cursor: pointer;
1012 1012 background-color: #b2d2ff;
1013 1013 }
1014 1014 .yui-skin-sam .yui-dt-list th.yui-dt-highlighted,
1015 1015 .yui-skin-sam .yui-dt-list th.yui-dt-highlighted a { background-color: #b2d2ff }
1016 1016 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted,
1017 1017 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-asc,
1018 1018 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-desc,
1019 1019 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-highlighted,
1020 1020 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-highlighted {
1021 1021 cursor: pointer;
1022 1022 background-color: #b2d2ff;
1023 1023 }
1024 1024 .yui-skin-sam th.yui-dt-selected,
1025 1025 .yui-skin-sam th.yui-dt-selected a { background-color: #446cd7 }
1026 1026 .yui-skin-sam tr.yui-dt-selected td,
1027 1027 .yui-skin-sam tr.yui-dt-selected td.yui-dt-asc,
1028 1028 .yui-skin-sam tr.yui-dt-selected td.yui-dt-desc {
1029 1029 background-color: #426fd9;
1030 1030 color: #FFF;
1031 1031 }
1032 1032 .yui-skin-sam tr.yui-dt-even td.yui-dt-selected,
1033 1033 .yui-skin-sam tr.yui-dt-odd td.yui-dt-selected {
1034 1034 background-color: #446cd7;
1035 1035 color: #FFF;
1036 1036 }
1037 1037 .yui-skin-sam .yui-dt-list th.yui-dt-selected,
1038 1038 .yui-skin-sam .yui-dt-list th.yui-dt-selected a { background-color: #446cd7 }
1039 1039 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td,
1040 1040 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-asc,
1041 1041 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-desc {
1042 1042 background-color: #426fd9;
1043 1043 color: #FFF;
1044 1044 }
1045 1045 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-selected,
1046 1046 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-selected {
1047 1047 background-color: #446cd7;
1048 1048 color: #FFF;
1049 1049 }
1050 1050 .yui-skin-sam .yui-dt-paginator {
1051 1051 display: block;
1052 1052 margin: 6px 0;
1053 1053 white-space: nowrap;
1054 1054 }
1055 1055 .yui-skin-sam .yui-dt-paginator .yui-dt-first,
1056 1056 .yui-skin-sam .yui-dt-paginator .yui-dt-last,
1057 1057 .yui-skin-sam .yui-dt-paginator .yui-dt-selected { padding: 2px 6px }
1058 1058 .yui-skin-sam .yui-dt-paginator a.yui-dt-first,
1059 1059 .yui-skin-sam .yui-dt-paginator a.yui-dt-last { text-decoration: none }
1060 1060 .yui-skin-sam .yui-dt-paginator .yui-dt-previous,
1061 1061 .yui-skin-sam .yui-dt-paginator .yui-dt-next { display: none }
1062 1062 .yui-skin-sam a.yui-dt-page {
1063 1063 border: 1px solid #cbcbcb;
1064 1064 padding: 2px 6px;
1065 1065 text-decoration: none;
1066 1066 background-color: #fff;
1067 1067 }
1068 1068 .yui-skin-sam .yui-dt-selected {
1069 1069 border: 1px solid #fff;
1070 1070 background-color: #fff;
1071 1071 }
1072 1072
1073 1073 #content #left {
1074 1074 left: 0;
1075 1075 width: 280px;
1076 1076 position: absolute;
1077 1077 }
1078 1078
1079 1079 #content #right {
1080 1080 margin: 0 60px 10px 290px;
1081 1081 }
1082 1082
1083 1083 #content div.box {
1084 1084 clear: both;
1085 1085 overflow: hidden;
1086 1086 background: #fff;
1087 1087 margin: 0 0 10px;
1088 1088 padding: 0 0 10px;
1089 1089 -webkit-border-radius: 4px 4px 4px 4px;
1090 1090 -khtml-border-radius: 4px 4px 4px 4px;
1091 1091 -moz-border-radius: 4px 4px 4px 4px;
1092 1092 border-radius: 4px 4px 4px 4px;
1093 1093 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
1094 1094 }
1095 1095
1096 1096 #content div.box-left {
1097 1097 width: 49%;
1098 1098 clear: none;
1099 1099 float: left;
1100 1100 margin: 0 0 10px;
1101 1101 }
1102 1102
1103 1103 #content div.box-right {
1104 1104 width: 49%;
1105 1105 clear: none;
1106 1106 float: right;
1107 1107 margin: 0 0 10px;
1108 1108 }
1109 1109
1110 1110 #content div.box div.title {
1111 1111 clear: both;
1112 1112 overflow: hidden;
1113 1113 background-color: #003B76;
1114 1114 background-repeat: repeat-x;
1115 1115 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
1116 1116 background-image: -moz-linear-gradient(top, #003b76, #00376e);
1117 1117 background-image: -ms-linear-gradient(top, #003b76, #00376e);
1118 1118 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
1119 1119 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
1120 1120 background-image: -o-linear-gradient(top, #003b76, #00376e);
1121 1121 background-image: linear-gradient(top, #003b76, #00376e);
1122 1122 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76', endColorstr='#00376e', GradientType=0 );
1123 1123 margin: 0 0 20px;
1124 1124 padding: 0;
1125 1125 }
1126 1126
1127 1127 #content div.box div.title h5 {
1128 1128 float: left;
1129 1129 border: none;
1130 1130 color: #fff;
1131 1131 text-transform: uppercase;
1132 1132 margin: 0;
1133 1133 padding: 11px 0 11px 10px;
1134 1134 }
1135 1135
1136 1136 #content div.box div.title .link-white{
1137 1137 color: #FFFFFF;
1138 1138 }
1139 1139
1140 1140 #content div.box div.title .link-white.current{
1141 1141 color: #BFE3FF;
1142 1142 }
1143 1143
1144 1144 #content div.box div.title ul.links li {
1145 1145 list-style: none;
1146 1146 float: left;
1147 1147 margin: 0;
1148 1148 padding: 0;
1149 1149 }
1150 1150
1151 1151 #content div.box div.title ul.links li a {
1152 1152 border-left: 1px solid #316293;
1153 1153 color: #FFFFFF;
1154 1154 display: block;
1155 1155 float: left;
1156 1156 font-size: 13px;
1157 1157 font-weight: 700;
1158 1158 height: 1%;
1159 1159 margin: 0;
1160 1160 padding: 11px 22px 12px;
1161 1161 text-decoration: none;
1162 1162 }
1163 1163
1164 1164 #content div.box h1,#content div.box h2,#content div.box h3,#content div.box h4,#content div.box h5,#content div.box h6,
1165 1165 #content div.box div.h1,#content div.box div.h2,#content div.box div.h3,#content div.box div.h4,#content div.box div.h5,#content div.box div.h6
1166 1166
1167 1167 {
1168 1168 clear: both;
1169 1169 overflow: hidden;
1170 1170 border-bottom: 1px solid #DDD;
1171 1171 margin: 10px 20px;
1172 1172 padding: 0 0 15px;
1173 1173 }
1174 1174
1175 1175 #content div.box p {
1176 1176 color: #5f5f5f;
1177 1177 font-size: 12px;
1178 1178 line-height: 150%;
1179 1179 margin: 0 24px 10px;
1180 1180 padding: 0;
1181 1181 }
1182 1182
1183 1183 #content div.box blockquote {
1184 1184 border-left: 4px solid #DDD;
1185 1185 color: #5f5f5f;
1186 1186 font-size: 11px;
1187 1187 line-height: 150%;
1188 1188 margin: 0 34px;
1189 1189 padding: 0 0 0 14px;
1190 1190 }
1191 1191
1192 1192 #content div.box blockquote p {
1193 1193 margin: 10px 0;
1194 1194 padding: 0;
1195 1195 }
1196 1196
1197 1197 #content div.box dl {
1198 1198 margin: 10px 0px;
1199 1199 }
1200 1200
1201 1201 #content div.box dt {
1202 1202 font-size: 12px;
1203 1203 margin: 0;
1204 1204 }
1205 1205
1206 1206 #content div.box dd {
1207 1207 font-size: 12px;
1208 1208 margin: 0;
1209 1209 padding: 8px 0 8px 15px;
1210 1210 }
1211 1211
1212 1212 #content div.box li {
1213 1213 font-size: 12px;
1214 1214 padding: 4px 0;
1215 1215 }
1216 1216
1217 1217 #content div.box ul.disc,#content div.box ul.circle {
1218 1218 margin: 10px 24px 10px 38px;
1219 1219 }
1220 1220
1221 1221 #content div.box ul.square {
1222 1222 margin: 10px 24px 10px 40px;
1223 1223 }
1224 1224
1225 1225 #content div.box img.left {
1226 1226 border: none;
1227 1227 float: left;
1228 1228 margin: 10px 10px 10px 0;
1229 1229 }
1230 1230
1231 1231 #content div.box img.right {
1232 1232 border: none;
1233 1233 float: right;
1234 1234 margin: 10px 0 10px 10px;
1235 1235 }
1236 1236
1237 1237 #content div.box div.messages {
1238 1238 clear: both;
1239 1239 overflow: hidden;
1240 1240 margin: 0 20px;
1241 1241 padding: 0;
1242 1242 }
1243 1243
1244 1244 #content div.box div.message {
1245 1245 clear: both;
1246 1246 overflow: hidden;
1247 1247 margin: 0;
1248 1248 padding: 5px 0;
1249 1249 white-space: pre-wrap;
1250 1250 }
1251 1251 #content div.box div.expand {
1252 1252 width: 110%;
1253 1253 height:14px;
1254 1254 font-size:10px;
1255 1255 text-align:center;
1256 1256 cursor: pointer;
1257 1257 color:#666;
1258 1258
1259 1259 background:-webkit-gradient(linear,0% 50%,100% 50%,color-stop(0%,rgba(255,255,255,0)),color-stop(100%,rgba(64,96,128,0.1)));
1260 1260 background:-webkit-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1261 1261 background:-moz-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1262 1262 background:-o-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1263 1263 background:-ms-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1264 1264 background:linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1265 1265
1266 1266 display: none;
1267 1267 }
1268 1268 #content div.box div.expand .expandtext {
1269 1269 background-color: #ffffff;
1270 1270 padding: 2px;
1271 1271 border-radius: 2px;
1272 1272 }
1273 1273
1274 1274 #content div.box div.message a {
1275 1275 font-weight: 400 !important;
1276 1276 }
1277 1277
1278 1278 #content div.box div.message div.image {
1279 1279 float: left;
1280 1280 margin: 9px 0 0 5px;
1281 1281 padding: 6px;
1282 1282 }
1283 1283
1284 1284 #content div.box div.message div.image img {
1285 1285 vertical-align: middle;
1286 1286 margin: 0;
1287 1287 }
1288 1288
1289 1289 #content div.box div.message div.text {
1290 1290 float: left;
1291 1291 margin: 0;
1292 1292 padding: 9px 6px;
1293 1293 }
1294 1294
1295 1295 #content div.box div.message div.dismiss a {
1296 1296 height: 16px;
1297 1297 width: 16px;
1298 1298 display: block;
1299 1299 background: url("../images/icons/cross.png") no-repeat;
1300 1300 margin: 15px 14px 0 0;
1301 1301 padding: 0;
1302 1302 }
1303 1303
1304 1304 #content div.box div.message div.text h1,#content div.box div.message div.text h2,#content div.box div.message div.text h3,#content div.box div.message div.text h4,#content div.box div.message div.text h5,#content div.box div.message div.text h6
1305 1305 {
1306 1306 border: none;
1307 1307 margin: 0;
1308 1308 padding: 0;
1309 1309 }
1310 1310
1311 1311 #content div.box div.message div.text span {
1312 1312 height: 1%;
1313 1313 display: block;
1314 1314 margin: 0;
1315 1315 padding: 5px 0 0;
1316 1316 }
1317 1317
1318 1318 #content div.box div.message-error {
1319 1319 height: 1%;
1320 1320 clear: both;
1321 1321 overflow: hidden;
1322 1322 background: #FBE3E4;
1323 1323 border: 1px solid #FBC2C4;
1324 1324 color: #860006;
1325 1325 }
1326 1326
1327 1327 #content div.box div.message-error h6 {
1328 1328 color: #860006;
1329 1329 }
1330 1330
1331 1331 #content div.box div.message-warning {
1332 1332 height: 1%;
1333 1333 clear: both;
1334 1334 overflow: hidden;
1335 1335 background: #FFF6BF;
1336 1336 border: 1px solid #FFD324;
1337 1337 color: #5f5200;
1338 1338 }
1339 1339
1340 1340 #content div.box div.message-warning h6 {
1341 1341 color: #5f5200;
1342 1342 }
1343 1343
1344 1344 #content div.box div.message-notice {
1345 1345 height: 1%;
1346 1346 clear: both;
1347 1347 overflow: hidden;
1348 1348 background: #8FBDE0;
1349 1349 border: 1px solid #6BACDE;
1350 1350 color: #003863;
1351 1351 }
1352 1352
1353 1353 #content div.box div.message-notice h6 {
1354 1354 color: #003863;
1355 1355 }
1356 1356
1357 1357 #content div.box div.message-success {
1358 1358 height: 1%;
1359 1359 clear: both;
1360 1360 overflow: hidden;
1361 1361 background: #E6EFC2;
1362 1362 border: 1px solid #C6D880;
1363 1363 color: #4e6100;
1364 1364 }
1365 1365
1366 1366 #content div.box div.message-success h6 {
1367 1367 color: #4e6100;
1368 1368 }
1369 1369
1370 1370 #content div.box div.form div.fields div.field {
1371 1371 height: 1%;
1372 1372 border-bottom: 1px solid #DDD;
1373 1373 clear: both;
1374 1374 margin: 0;
1375 1375 padding: 10px 0;
1376 1376 }
1377 1377
1378 1378 #content div.box div.form div.fields div.field-first {
1379 1379 padding: 0 0 10px;
1380 1380 }
1381 1381
1382 1382 #content div.box div.form div.fields div.field-noborder {
1383 1383 border-bottom: 0 !important;
1384 1384 }
1385 1385
1386 1386 #content div.box div.form div.fields div.field span.error-message {
1387 1387 height: 1%;
1388 1388 display: inline-block;
1389 1389 color: red;
1390 1390 margin: 8px 0 0 4px;
1391 1391 padding: 0;
1392 1392 }
1393 1393
1394 1394 #content div.box div.form div.fields div.field span.success {
1395 1395 height: 1%;
1396 1396 display: block;
1397 1397 color: #316309;
1398 1398 margin: 8px 0 0;
1399 1399 padding: 0;
1400 1400 }
1401 1401
1402 1402 #content div.box div.form div.fields div.field div.label {
1403 1403 left: 70px;
1404 1404 width: 155px;
1405 1405 position: absolute;
1406 1406 margin: 0;
1407 1407 padding: 5px 0 0 0px;
1408 1408 }
1409 1409
1410 1410 #content div.box div.form div.fields div.field div.label-summary {
1411 1411 left: 30px;
1412 1412 width: 155px;
1413 1413 position: absolute;
1414 1414 margin: 0;
1415 1415 padding: 0px 0 0 0px;
1416 1416 }
1417 1417
1418 1418 #content div.box-left div.form div.fields div.field div.label,
1419 1419 #content div.box-right div.form div.fields div.field div.label,
1420 1420 #content div.box-left div.form div.fields div.field div.label,
1421 1421 #content div.box-left div.form div.fields div.field div.label-summary,
1422 1422 #content div.box-right div.form div.fields div.field div.label-summary,
1423 1423 #content div.box-left div.form div.fields div.field div.label-summary
1424 1424 {
1425 1425 clear: both;
1426 1426 overflow: hidden;
1427 1427 left: 0;
1428 1428 width: auto;
1429 1429 position: relative;
1430 1430 margin: 0;
1431 1431 padding: 0 0 8px;
1432 1432 }
1433 1433
1434 1434 #content div.box div.form div.fields div.field div.label-select {
1435 1435 padding: 5px 0 0 5px;
1436 1436 }
1437 1437
1438 1438 #content div.box-left div.form div.fields div.field div.label-select,
1439 1439 #content div.box-right div.form div.fields div.field div.label-select
1440 1440 {
1441 1441 padding: 0 0 8px;
1442 1442 }
1443 1443
1444 1444 #content div.box-left div.form div.fields div.field div.label-textarea,
1445 1445 #content div.box-right div.form div.fields div.field div.label-textarea
1446 1446 {
1447 1447 padding: 0 0 8px !important;
1448 1448 }
1449 1449
1450 1450 #content div.box div.form div.fields div.field div.label label,div.label label
1451 1451 {
1452 1452 color: #393939;
1453 1453 font-weight: 700;
1454 1454 }
1455 1455 #content div.box div.form div.fields div.field div.label label,div.label-summary label
1456 1456 {
1457 1457 color: #393939;
1458 1458 font-weight: 700;
1459 1459 }
1460 1460 #content div.box div.form div.fields div.field div.input {
1461 1461 margin: 0 0 0 200px;
1462 1462 }
1463 1463
1464 1464 #content div.box div.form div.fields div.field div.input.summary {
1465 1465 margin: 0 0 0 110px;
1466 1466 }
1467 1467 #content div.box div.form div.fields div.field div.input.summary-short {
1468 1468 margin: 0 0 0 110px;
1469 1469 }
1470 1470 #content div.box div.form div.fields div.field div.file {
1471 1471 margin: 0 0 0 200px;
1472 1472 }
1473 1473
1474 1474 #content div.box-left div.form div.fields div.field div.input,#content div.box-right div.form div.fields div.field div.input
1475 1475 {
1476 1476 margin: 0 0 0 0px;
1477 1477 }
1478 1478
1479 1479 #content div.box div.form div.fields div.field div.input input,
1480 1480 .reviewer_ac input {
1481 1481 background: #FFF;
1482 1482 border-top: 1px solid #b3b3b3;
1483 1483 border-left: 1px solid #b3b3b3;
1484 1484 border-right: 1px solid #eaeaea;
1485 1485 border-bottom: 1px solid #eaeaea;
1486 1486 color: #000;
1487 1487 font-size: 11px;
1488 1488 margin: 0;
1489 1489 padding: 7px 7px 6px;
1490 1490 }
1491 1491
1492 1492 #content div.box div.form div.fields div.field div.input input#clone_url,
1493 1493 #content div.box div.form div.fields div.field div.input input#clone_url_id
1494 1494 {
1495 1495 font-size: 16px;
1496 1496 padding: 2px;
1497 1497 }
1498 1498
1499 1499 #content div.box div.form div.fields div.field div.file input {
1500 1500 background: none repeat scroll 0 0 #FFFFFF;
1501 1501 border-color: #B3B3B3 #EAEAEA #EAEAEA #B3B3B3;
1502 1502 border-style: solid;
1503 1503 border-width: 1px;
1504 1504 color: #000000;
1505 1505 font-size: 11px;
1506 1506 margin: 0;
1507 1507 padding: 7px 7px 6px;
1508 1508 }
1509 1509
1510 1510 input.disabled {
1511 1511 background-color: #F5F5F5 !important;
1512 1512 }
1513 1513 #content div.box div.form div.fields div.field div.input input.small {
1514 1514 width: 30%;
1515 1515 }
1516 1516
1517 1517 #content div.box div.form div.fields div.field div.input input.medium {
1518 1518 width: 55%;
1519 1519 }
1520 1520
1521 1521 #content div.box div.form div.fields div.field div.input input.large {
1522 1522 width: 85%;
1523 1523 }
1524 1524
1525 1525 #content div.box div.form div.fields div.field div.input input.date {
1526 1526 width: 177px;
1527 1527 }
1528 1528
1529 1529 #content div.box div.form div.fields div.field div.input input.button {
1530 1530 background: #D4D0C8;
1531 1531 border-top: 1px solid #FFF;
1532 1532 border-left: 1px solid #FFF;
1533 1533 border-right: 1px solid #404040;
1534 1534 border-bottom: 1px solid #404040;
1535 1535 color: #000;
1536 1536 margin: 0;
1537 1537 padding: 4px 8px;
1538 1538 }
1539 1539
1540 1540 #content div.box div.form div.fields div.field div.textarea {
1541 1541 border-top: 1px solid #b3b3b3;
1542 1542 border-left: 1px solid #b3b3b3;
1543 1543 border-right: 1px solid #eaeaea;
1544 1544 border-bottom: 1px solid #eaeaea;
1545 1545 margin: 0 0 0 200px;
1546 1546 padding: 10px;
1547 1547 }
1548 1548
1549 1549 #content div.box div.form div.fields div.field div.textarea-editor {
1550 1550 border: 1px solid #ddd;
1551 1551 padding: 0;
1552 1552 }
1553 1553
1554 1554 #content div.box div.form div.fields div.field div.textarea textarea {
1555 1555 width: 100%;
1556 1556 height: 220px;
1557 1557 overflow: hidden;
1558 1558 background: #FFF;
1559 1559 color: #000;
1560 1560 font-size: 11px;
1561 1561 outline: none;
1562 1562 border-width: 0;
1563 1563 margin: 0;
1564 1564 padding: 0;
1565 1565 }
1566 1566
1567 1567 #content div.box-left div.form div.fields div.field div.textarea textarea,#content div.box-right div.form div.fields div.field div.textarea textarea
1568 1568 {
1569 1569 width: 100%;
1570 1570 height: 100px;
1571 1571 }
1572 1572
1573 1573 #content div.box div.form div.fields div.field div.textarea table {
1574 1574 width: 100%;
1575 1575 border: none;
1576 1576 margin: 0;
1577 1577 padding: 0;
1578 1578 }
1579 1579
1580 1580 #content div.box div.form div.fields div.field div.textarea table td {
1581 1581 background: #DDD;
1582 1582 border: none;
1583 1583 padding: 0;
1584 1584 }
1585 1585
1586 1586 #content div.box div.form div.fields div.field div.textarea table td table
1587 1587 {
1588 1588 width: auto;
1589 1589 border: none;
1590 1590 margin: 0;
1591 1591 padding: 0;
1592 1592 }
1593 1593
1594 1594 #content div.box div.form div.fields div.field div.textarea table td table td
1595 1595 {
1596 1596 font-size: 11px;
1597 1597 padding: 5px 5px 5px 0;
1598 1598 }
1599 1599
1600 1600 #content div.box div.form div.fields div.field input[type=text]:focus,
1601 1601 #content div.box div.form div.fields div.field input[type=password]:focus,
1602 1602 #content div.box div.form div.fields div.field input[type=file]:focus,
1603 1603 #content div.box div.form div.fields div.field textarea:focus,
1604 1604 #content div.box div.form div.fields div.field select:focus,
1605 1605 .reviewer_ac input:focus
1606 1606 {
1607 1607 background: #f6f6f6;
1608 1608 border-color: #666;
1609 1609 }
1610 1610
1611 1611 .reviewer_ac {
1612 1612 padding:10px
1613 1613 }
1614 1614
1615 1615 div.form div.fields div.field div.button {
1616 1616 margin: 0;
1617 1617 padding: 0 0 0 8px;
1618 1618 }
1619 1619 #content div.box table.noborder {
1620 1620 border: 1px solid transparent;
1621 1621 }
1622 1622
1623 1623 #content div.box table {
1624 1624 width: 100%;
1625 1625 border-collapse: separate;
1626 1626 margin: 0;
1627 1627 padding: 0;
1628 1628 border: 1px solid #eee;
1629 1629 -webkit-border-radius: 4px;
1630 1630 -moz-border-radius: 4px;
1631 1631 border-radius: 4px;
1632 1632 }
1633 1633
1634 1634 #content div.box table th {
1635 1635 background: #eee;
1636 1636 border-bottom: 1px solid #ddd;
1637 1637 padding: 5px 0px 5px 5px;
1638 1638 text-align: left;
1639 1639 }
1640 1640
1641 1641 #content div.box table th.left {
1642 1642 text-align: left;
1643 1643 }
1644 1644
1645 1645 #content div.box table th.right {
1646 1646 text-align: right;
1647 1647 }
1648 1648
1649 1649 #content div.box table th.center {
1650 1650 text-align: center;
1651 1651 }
1652 1652
1653 1653 #content div.box table th.selected {
1654 1654 vertical-align: middle;
1655 1655 padding: 0;
1656 1656 }
1657 1657
1658 1658 #content div.box table td {
1659 1659 background: #fff;
1660 1660 border-bottom: 1px solid #cdcdcd;
1661 1661 vertical-align: middle;
1662 1662 padding: 5px;
1663 1663 }
1664 1664
1665 1665 #content div.box table tr.selected td {
1666 1666 background: #FFC;
1667 1667 }
1668 1668
1669 1669 #content div.box table td.selected {
1670 1670 width: 3%;
1671 1671 text-align: center;
1672 1672 vertical-align: middle;
1673 1673 padding: 0;
1674 1674 }
1675 1675
1676 1676 #content div.box table td.action {
1677 1677 width: 45%;
1678 1678 text-align: left;
1679 1679 }
1680 1680
1681 1681 #content div.box table td.date {
1682 1682 width: 33%;
1683 1683 text-align: center;
1684 1684 }
1685 1685
1686 1686 #content div.box div.action {
1687 1687 float: right;
1688 1688 background: #FFF;
1689 1689 text-align: right;
1690 1690 margin: 10px 0 0;
1691 1691 padding: 0;
1692 1692 }
1693 1693
1694 1694 #content div.box div.action select {
1695 1695 font-size: 11px;
1696 1696 margin: 0;
1697 1697 }
1698 1698
1699 1699 #content div.box div.action .ui-selectmenu {
1700 1700 margin: 0;
1701 1701 padding: 0;
1702 1702 }
1703 1703
1704 1704 #content div.box div.pagination {
1705 1705 height: 1%;
1706 1706 clear: both;
1707 1707 overflow: hidden;
1708 1708 margin: 10px 0 0;
1709 1709 padding: 0;
1710 1710 }
1711 1711
1712 1712 #content div.box div.pagination ul.pager {
1713 1713 float: right;
1714 1714 text-align: right;
1715 1715 margin: 0;
1716 1716 padding: 0;
1717 1717 }
1718 1718
1719 1719 #content div.box div.pagination ul.pager li {
1720 1720 height: 1%;
1721 1721 float: left;
1722 1722 list-style: none;
1723 1723 background: #ebebeb url("../images/pager.png") repeat-x;
1724 1724 border-top: 1px solid #dedede;
1725 1725 border-left: 1px solid #cfcfcf;
1726 1726 border-right: 1px solid #c4c4c4;
1727 1727 border-bottom: 1px solid #c4c4c4;
1728 1728 color: #4A4A4A;
1729 1729 font-weight: 700;
1730 1730 margin: 0 0 0 4px;
1731 1731 padding: 0;
1732 1732 }
1733 1733
1734 1734 #content div.box div.pagination ul.pager li.separator {
1735 1735 padding: 6px;
1736 1736 }
1737 1737
1738 1738 #content div.box div.pagination ul.pager li.current {
1739 1739 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1740 1740 border-top: 1px solid #ccc;
1741 1741 border-left: 1px solid #bebebe;
1742 1742 border-right: 1px solid #b1b1b1;
1743 1743 border-bottom: 1px solid #afafaf;
1744 1744 color: #515151;
1745 1745 padding: 6px;
1746 1746 }
1747 1747
1748 1748 #content div.box div.pagination ul.pager li a {
1749 1749 height: 1%;
1750 1750 display: block;
1751 1751 float: left;
1752 1752 color: #515151;
1753 1753 text-decoration: none;
1754 1754 margin: 0;
1755 1755 padding: 6px;
1756 1756 }
1757 1757
1758 1758 #content div.box div.pagination ul.pager li a:hover,#content div.box div.pagination ul.pager li a:active
1759 1759 {
1760 1760 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1761 1761 border-top: 1px solid #ccc;
1762 1762 border-left: 1px solid #bebebe;
1763 1763 border-right: 1px solid #b1b1b1;
1764 1764 border-bottom: 1px solid #afafaf;
1765 1765 margin: -1px;
1766 1766 }
1767 1767
1768 1768 #content div.box div.pagination-wh {
1769 1769 height: 1%;
1770 1770 clear: both;
1771 1771 overflow: hidden;
1772 1772 text-align: right;
1773 1773 margin: 10px 0 0;
1774 1774 padding: 0;
1775 1775 }
1776 1776
1777 1777 #content div.box div.pagination-right {
1778 1778 float: right;
1779 1779 }
1780 1780
1781 1781 #content div.box div.pagination-wh a,
1782 1782 #content div.box div.pagination-wh span.pager_dotdot,
1783 1783 #content div.box div.pagination-wh span.yui-pg-previous,
1784 1784 #content div.box div.pagination-wh span.yui-pg-last,
1785 1785 #content div.box div.pagination-wh span.yui-pg-next,
1786 1786 #content div.box div.pagination-wh span.yui-pg-first
1787 1787 {
1788 1788 height: 1%;
1789 1789 float: left;
1790 1790 background: #ebebeb url("../images/pager.png") repeat-x;
1791 1791 border-top: 1px solid #dedede;
1792 1792 border-left: 1px solid #cfcfcf;
1793 1793 border-right: 1px solid #c4c4c4;
1794 1794 border-bottom: 1px solid #c4c4c4;
1795 1795 color: #4A4A4A;
1796 1796 font-weight: 700;
1797 1797 margin: 0 0 0 4px;
1798 1798 padding: 6px;
1799 1799 }
1800 1800
1801 1801 #content div.box div.pagination-wh span.pager_curpage {
1802 1802 height: 1%;
1803 1803 float: left;
1804 1804 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1805 1805 border-top: 1px solid #ccc;
1806 1806 border-left: 1px solid #bebebe;
1807 1807 border-right: 1px solid #b1b1b1;
1808 1808 border-bottom: 1px solid #afafaf;
1809 1809 color: #515151;
1810 1810 font-weight: 700;
1811 1811 margin: 0 0 0 4px;
1812 1812 padding: 6px;
1813 1813 }
1814 1814
1815 1815 #content div.box div.pagination-wh a:hover,#content div.box div.pagination-wh a:active
1816 1816 {
1817 1817 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1818 1818 border-top: 1px solid #ccc;
1819 1819 border-left: 1px solid #bebebe;
1820 1820 border-right: 1px solid #b1b1b1;
1821 1821 border-bottom: 1px solid #afafaf;
1822 1822 text-decoration: none;
1823 1823 }
1824 1824
1825 1825 #content div.box div.traffic div.legend {
1826 1826 clear: both;
1827 1827 overflow: hidden;
1828 1828 border-bottom: 1px solid #ddd;
1829 1829 margin: 0 0 10px;
1830 1830 padding: 0 0 10px;
1831 1831 }
1832 1832
1833 1833 #content div.box div.traffic div.legend h6 {
1834 1834 float: left;
1835 1835 border: none;
1836 1836 margin: 0;
1837 1837 padding: 0;
1838 1838 }
1839 1839
1840 1840 #content div.box div.traffic div.legend li {
1841 1841 list-style: none;
1842 1842 float: left;
1843 1843 font-size: 11px;
1844 1844 margin: 0;
1845 1845 padding: 0 8px 0 4px;
1846 1846 }
1847 1847
1848 1848 #content div.box div.traffic div.legend li.visits {
1849 1849 border-left: 12px solid #edc240;
1850 1850 }
1851 1851
1852 1852 #content div.box div.traffic div.legend li.pageviews {
1853 1853 border-left: 12px solid #afd8f8;
1854 1854 }
1855 1855
1856 1856 #content div.box div.traffic table {
1857 1857 width: auto;
1858 1858 }
1859 1859
1860 1860 #content div.box div.traffic table td {
1861 1861 background: transparent;
1862 1862 border: none;
1863 1863 padding: 2px 3px 3px;
1864 1864 }
1865 1865
1866 1866 #content div.box div.traffic table td.legendLabel {
1867 1867 padding: 0 3px 2px;
1868 1868 }
1869 1869
1870 1870 #summary {
1871 1871
1872 1872 }
1873 1873
1874 1874 #summary .metatag {
1875 1875 display: inline-block;
1876 1876 padding: 3px 5px;
1877 1877 margin-bottom: 3px;
1878 1878 margin-right: 1px;
1879 1879 border-radius: 5px;
1880 1880 }
1881 1881
1882 1882 #content div.box #summary p {
1883 1883 margin-bottom: -5px;
1884 1884 width: 600px;
1885 1885 white-space: pre-wrap;
1886 1886 }
1887 1887
1888 1888 #content div.box #summary p:last-child {
1889 1889 margin-bottom: 9px;
1890 1890 }
1891 1891
1892 1892 #content div.box #summary p:first-of-type {
1893 1893 margin-top: 9px;
1894 1894 }
1895 1895
1896 1896 .metatag {
1897 1897 display: inline-block;
1898 1898 margin-right: 1px;
1899 1899 -webkit-border-radius: 4px 4px 4px 4px;
1900 1900 -khtml-border-radius: 4px 4px 4px 4px;
1901 1901 -moz-border-radius: 4px 4px 4px 4px;
1902 1902 border-radius: 4px 4px 4px 4px;
1903 1903
1904 1904 border: solid 1px #9CF;
1905 1905 padding: 2px 3px 2px 3px !important;
1906 1906 background-color: #DEF;
1907 1907 }
1908 1908
1909 1909 .metatag[tag="dead"] {
1910 1910 background-color: #E44;
1911 1911 }
1912 1912
1913 1913 .metatag[tag="stale"] {
1914 1914 background-color: #EA4;
1915 1915 }
1916 1916
1917 1917 .metatag[tag="featured"] {
1918 1918 background-color: #AEA;
1919 1919 }
1920 1920
1921 1921 .metatag[tag="requires"] {
1922 1922 background-color: #9CF;
1923 1923 }
1924 1924
1925 1925 .metatag[tag="recommends"] {
1926 1926 background-color: #BDF;
1927 1927 }
1928 1928
1929 1929 .metatag[tag="lang"] {
1930 1930 background-color: #FAF474;
1931 1931 }
1932 1932
1933 1933 .metatag[tag="license"] {
1934 1934 border: solid 1px #9CF;
1935 1935 background-color: #DEF;
1936 1936 target-new: tab !important;
1937 1937 }
1938 1938 .metatag[tag="see"] {
1939 1939 border: solid 1px #CBD;
1940 1940 background-color: #EDF;
1941 1941 }
1942 1942
1943 1943 a.metatag[tag="license"]:hover {
1944 1944 background-color: #003367;
1945 1945 color: #FFF;
1946 1946 text-decoration: none;
1947 1947 }
1948 1948
1949 1949 #summary .desc {
1950 1950 white-space: pre;
1951 1951 width: 100%;
1952 1952 }
1953 1953
1954 1954 #summary .repo_name {
1955 1955 font-size: 1.6em;
1956 1956 font-weight: bold;
1957 1957 vertical-align: baseline;
1958 1958 clear: right
1959 1959 }
1960 1960
1961 1961 #footer {
1962 1962 clear: both;
1963 1963 overflow: hidden;
1964 1964 text-align: right;
1965 1965 margin: 0;
1966 1966 padding: 0 10px 4px;
1967 1967 margin: -10px 0 0;
1968 1968 }
1969 1969
1970 1970 #footer div#footer-inner {
1971 1971 background-color: #003B76;
1972 1972 background-repeat : repeat-x;
1973 1973 background-image : -khtml-gradient( linear, left top, left bottom, from(#003B76), to(#00376E));
1974 1974 background-image : -moz-linear-gradient(top, #003b76, #00376e);
1975 1975 background-image : -ms-linear-gradient( top, #003b76, #00376e);
1976 1976 background-image : -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #003b76), color-stop( 100%, #00376e));
1977 1977 background-image : -webkit-linear-gradient( top, #003b76, #00376e));
1978 1978 background-image : -o-linear-gradient( top, #003b76, #00376e));
1979 1979 background-image : linear-gradient( top, #003b76, #00376e);
1980 1980 filter :progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#003b76', endColorstr = '#00376e', GradientType = 0);
1981 1981 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
1982 1982 -webkit-border-radius: 4px 4px 4px 4px;
1983 1983 -khtml-border-radius: 4px 4px 4px 4px;
1984 1984 -moz-border-radius: 4px 4px 4px 4px;
1985 1985 border-radius: 4px 4px 4px 4px;
1986 1986 }
1987 1987
1988 1988 #footer div#footer-inner p {
1989 1989 padding: 15px 25px 15px 0;
1990 1990 color: #FFF;
1991 1991 font-weight: 700;
1992 1992 }
1993 1993
1994 1994 #footer div#footer-inner .footer-link {
1995 1995 float: left;
1996 1996 padding-left: 10px;
1997 1997 }
1998 1998
1999 1999 #footer div#footer-inner .footer-link a,#footer div#footer-inner .footer-link-right a
2000 2000 {
2001 2001 color: #FFF;
2002 2002 }
2003 2003
2004 2004 #login div.title {
2005 2005 clear: both;
2006 2006 overflow: hidden;
2007 2007 position: relative;
2008 2008 background-color: #003B76;
2009 2009 background-repeat : repeat-x;
2010 2010 background-image : -khtml-gradient( linear, left top, left bottom, from(#003B76), to(#00376E));
2011 2011 background-image : -moz-linear-gradient( top, #003b76, #00376e);
2012 2012 background-image : -ms-linear-gradient( top, #003b76, #00376e);
2013 2013 background-image : -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #003b76), color-stop( 100%, #00376e));
2014 2014 background-image : -webkit-linear-gradient( top, #003b76, #00376e));
2015 2015 background-image : -o-linear-gradient( top, #003b76, #00376e));
2016 2016 background-image : linear-gradient( top, #003b76, #00376e);
2017 2017 filter : progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#003b76', endColorstr = '#00376e', GradientType = 0);
2018 2018 margin: 0 auto;
2019 2019 padding: 0;
2020 2020 }
2021 2021
2022 2022 #login div.inner {
2023 2023 background: #FFF url("../images/login.png") no-repeat top left;
2024 2024 border-top: none;
2025 2025 border-bottom: none;
2026 2026 margin: 0 auto;
2027 2027 padding: 20px;
2028 2028 }
2029 2029
2030 2030 #login div.form div.fields div.field div.label {
2031 2031 width: 173px;
2032 2032 float: left;
2033 2033 text-align: right;
2034 2034 margin: 2px 10px 0 0;
2035 2035 padding: 5px 0 0 5px;
2036 2036 }
2037 2037
2038 2038 #login div.form div.fields div.field div.input input {
2039 2039 background: #FFF;
2040 2040 border-top: 1px solid #b3b3b3;
2041 2041 border-left: 1px solid #b3b3b3;
2042 2042 border-right: 1px solid #eaeaea;
2043 2043 border-bottom: 1px solid #eaeaea;
2044 2044 color: #000;
2045 2045 font-size: 11px;
2046 2046 margin: 0;
2047 2047 padding: 7px 7px 6px;
2048 2048 }
2049 2049
2050 2050 #login div.form div.fields div.buttons {
2051 2051 clear: both;
2052 2052 overflow: hidden;
2053 2053 border-top: 1px solid #DDD;
2054 2054 text-align: right;
2055 2055 margin: 0;
2056 2056 padding: 10px 0 0;
2057 2057 }
2058 2058
2059 2059 #login div.form div.links {
2060 2060 clear: both;
2061 2061 overflow: hidden;
2062 2062 margin: 10px 0 0;
2063 2063 padding: 0 0 2px;
2064 2064 }
2065 2065
2066 2066 .user-menu{
2067 2067 margin: 0px !important;
2068 2068 float: left;
2069 2069 }
2070 2070
2071 2071 .user-menu .container{
2072 2072 padding:0px 4px 0px 4px;
2073 2073 margin: 0px 0px 0px 0px;
2074 2074 }
2075 2075
2076 2076 .user-menu .gravatar{
2077 2077 margin: 0px 0px 0px 0px;
2078 2078 cursor: pointer;
2079 2079 }
2080 2080 .user-menu .gravatar.enabled{
2081 2081 background-color: #FDF784 !important;
2082 2082 }
2083 2083 .user-menu .gravatar:hover{
2084 2084 background-color: #FDF784 !important;
2085 2085 }
2086 2086 #quick_login{
2087 2087 min-height: 80px;
2088 2088 margin: 37px 0 0 -251px;
2089 2089 padding: 4px;
2090 2090 position: absolute;
2091 2091 width: 278px;
2092 2092 background-color: #003B76;
2093 2093 background-repeat: repeat-x;
2094 2094 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
2095 2095 background-image: -moz-linear-gradient(top, #003b76, #00376e);
2096 2096 background-image: -ms-linear-gradient(top, #003b76, #00376e);
2097 2097 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
2098 2098 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
2099 2099 background-image: -o-linear-gradient(top, #003b76, #00376e);
2100 2100 background-image: linear-gradient(top, #003b76, #00376e);
2101 2101 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76', endColorstr='#00376e', GradientType=0 );
2102 2102
2103 2103 z-index: 999;
2104 2104 -webkit-border-radius: 0px 0px 4px 4px;
2105 2105 -khtml-border-radius: 0px 0px 4px 4px;
2106 2106 -moz-border-radius: 0px 0px 4px 4px;
2107 2107 border-radius: 0px 0px 4px 4px;
2108 2108 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
2109 2109 }
2110 2110 #quick_login h4{
2111 2111 color: #fff;
2112 2112 padding: 5px 0px 5px 14px;
2113 2113 }
2114 2114
2115 2115 #quick_login .password_forgoten {
2116 2116 padding-right: 10px;
2117 2117 padding-top: 0px;
2118 2118 text-align: left;
2119 2119 }
2120 2120
2121 2121 #quick_login .password_forgoten a {
2122 2122 font-size: 10px;
2123 2123 color: #fff;
2124 2124 }
2125 2125
2126 2126 #quick_login .register {
2127 2127 padding-right: 10px;
2128 2128 padding-top: 5px;
2129 2129 text-align: left;
2130 2130 }
2131 2131
2132 2132 #quick_login .register a {
2133 2133 font-size: 10px;
2134 2134 color: #fff;
2135 2135 }
2136 2136
2137 2137 #quick_login .submit {
2138 2138 margin: -20px 0 0 0px;
2139 2139 position: absolute;
2140 2140 right: 15px;
2141 2141 }
2142 2142
2143 2143 #quick_login .links_left{
2144 2144 float: left;
2145 2145 }
2146 2146 #quick_login .links_right{
2147 2147 float: right;
2148 2148 }
2149 2149 #quick_login .full_name{
2150 2150 color: #FFFFFF;
2151 2151 font-weight: bold;
2152 2152 padding: 3px;
2153 2153 }
2154 2154 #quick_login .big_gravatar{
2155 2155 padding:4px 0px 0px 6px;
2156 2156 }
2157 2157 #quick_login .inbox{
2158 2158 padding:4px 0px 0px 6px;
2159 2159 color: #FFFFFF;
2160 2160 font-weight: bold;
2161 2161 }
2162 2162 #quick_login .inbox a{
2163 2163 color: #FFFFFF;
2164 2164 }
2165 2165 #quick_login .email,#quick_login .email a{
2166 2166 color: #FFFFFF;
2167 2167 padding: 3px;
2168 2168
2169 2169 }
2170 2170 #quick_login .links .logout{
2171 2171
2172 2172 }
2173 2173
2174 2174 #quick_login div.form div.fields {
2175 2175 padding-top: 2px;
2176 2176 padding-left: 10px;
2177 2177 }
2178 2178
2179 2179 #quick_login div.form div.fields div.field {
2180 2180 padding: 5px;
2181 2181 }
2182 2182
2183 2183 #quick_login div.form div.fields div.field div.label label {
2184 2184 color: #fff;
2185 2185 padding-bottom: 3px;
2186 2186 }
2187 2187
2188 2188 #quick_login div.form div.fields div.field div.input input {
2189 2189 width: 236px;
2190 2190 background: #FFF;
2191 2191 border-top: 1px solid #b3b3b3;
2192 2192 border-left: 1px solid #b3b3b3;
2193 2193 border-right: 1px solid #eaeaea;
2194 2194 border-bottom: 1px solid #eaeaea;
2195 2195 color: #000;
2196 2196 font-size: 11px;
2197 2197 margin: 0;
2198 2198 padding: 5px 7px 4px;
2199 2199 }
2200 2200
2201 2201 #quick_login div.form div.fields div.buttons {
2202 2202 clear: both;
2203 2203 overflow: hidden;
2204 2204 text-align: right;
2205 2205 margin: 0;
2206 2206 padding: 5px 14px 0px 5px;
2207 2207 }
2208 2208
2209 2209 #quick_login div.form div.links {
2210 2210 clear: both;
2211 2211 overflow: hidden;
2212 2212 margin: 10px 0 0;
2213 2213 padding: 0 0 2px;
2214 2214 }
2215 2215
2216 2216 #quick_login ol.links{
2217 2217 display: block;
2218 2218 font-weight: bold;
2219 2219 list-style: none outside none;
2220 2220 text-align: right;
2221 2221 }
2222 2222 #quick_login ol.links li{
2223 2223 line-height: 27px;
2224 2224 margin: 0;
2225 2225 padding: 0;
2226 2226 color: #fff;
2227 2227 display: block;
2228 2228 float:none !important;
2229 2229 }
2230 2230
2231 2231 #quick_login ol.links li a{
2232 2232 color: #fff;
2233 2233 display: block;
2234 2234 padding: 2px;
2235 2235 }
2236 2236 #quick_login ol.links li a:HOVER{
2237 2237 background-color: inherit !important;
2238 2238 }
2239 2239
2240 2240 #register div.title {
2241 2241 clear: both;
2242 2242 overflow: hidden;
2243 2243 position: relative;
2244 2244 background-color: #003B76;
2245 2245 background-repeat: repeat-x;
2246 2246 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
2247 2247 background-image: -moz-linear-gradient(top, #003b76, #00376e);
2248 2248 background-image: -ms-linear-gradient(top, #003b76, #00376e);
2249 2249 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
2250 2250 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
2251 2251 background-image: -o-linear-gradient(top, #003b76, #00376e);
2252 2252 background-image: linear-gradient(top, #003b76, #00376e);
2253 2253 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',
2254 2254 endColorstr='#00376e', GradientType=0 );
2255 2255 margin: 0 auto;
2256 2256 padding: 0;
2257 2257 }
2258 2258
2259 2259 #register div.inner {
2260 2260 background: #FFF;
2261 2261 border-top: none;
2262 2262 border-bottom: none;
2263 2263 margin: 0 auto;
2264 2264 padding: 20px;
2265 2265 }
2266 2266
2267 2267 #register div.form div.fields div.field div.label {
2268 2268 width: 135px;
2269 2269 float: left;
2270 2270 text-align: right;
2271 2271 margin: 2px 10px 0 0;
2272 2272 padding: 5px 0 0 5px;
2273 2273 }
2274 2274
2275 2275 #register div.form div.fields div.field div.input input {
2276 2276 width: 300px;
2277 2277 background: #FFF;
2278 2278 border-top: 1px solid #b3b3b3;
2279 2279 border-left: 1px solid #b3b3b3;
2280 2280 border-right: 1px solid #eaeaea;
2281 2281 border-bottom: 1px solid #eaeaea;
2282 2282 color: #000;
2283 2283 font-size: 11px;
2284 2284 margin: 0;
2285 2285 padding: 7px 7px 6px;
2286 2286 }
2287 2287
2288 2288 #register div.form div.fields div.buttons {
2289 2289 clear: both;
2290 2290 overflow: hidden;
2291 2291 border-top: 1px solid #DDD;
2292 2292 text-align: left;
2293 2293 margin: 0;
2294 2294 padding: 10px 0 0 150px;
2295 2295 }
2296 2296
2297 2297 #register div.form div.activation_msg {
2298 2298 padding-top: 4px;
2299 2299 padding-bottom: 4px;
2300 2300 }
2301 2301
2302 2302 #journal .journal_day {
2303 2303 font-size: 20px;
2304 2304 padding: 10px 0px;
2305 2305 border-bottom: 2px solid #DDD;
2306 2306 margin-left: 10px;
2307 2307 margin-right: 10px;
2308 2308 }
2309 2309
2310 2310 #journal .journal_container {
2311 2311 padding: 5px;
2312 2312 clear: both;
2313 2313 margin: 0px 5px 0px 10px;
2314 2314 }
2315 2315
2316 2316 #journal .journal_action_container {
2317 2317 padding-left: 38px;
2318 2318 }
2319 2319
2320 2320 #journal .journal_user {
2321 2321 color: #747474;
2322 2322 font-size: 14px;
2323 2323 font-weight: bold;
2324 2324 height: 30px;
2325 2325 }
2326 2326
2327 2327 #journal .journal_user.deleted {
2328 2328 color: #747474;
2329 2329 font-size: 14px;
2330 2330 font-weight: normal;
2331 2331 height: 30px;
2332 2332 font-style: italic;
2333 2333 }
2334 2334
2335 2335
2336 2336 #journal .journal_icon {
2337 2337 clear: both;
2338 2338 float: left;
2339 2339 padding-right: 4px;
2340 2340 padding-top: 3px;
2341 2341 }
2342 2342
2343 2343 #journal .journal_action {
2344 2344 padding-top: 4px;
2345 2345 min-height: 2px;
2346 2346 float: left
2347 2347 }
2348 2348
2349 2349 #journal .journal_action_params {
2350 2350 clear: left;
2351 2351 padding-left: 22px;
2352 2352 }
2353 2353
2354 2354 #journal .journal_repo {
2355 2355 float: left;
2356 2356 margin-left: 6px;
2357 2357 padding-top: 3px;
2358 2358 }
2359 2359
2360 2360 #journal .date {
2361 2361 clear: both;
2362 2362 color: #777777;
2363 2363 font-size: 11px;
2364 2364 padding-left: 22px;
2365 2365 }
2366 2366
2367 2367 #journal .journal_repo .journal_repo_name {
2368 2368 font-weight: bold;
2369 2369 font-size: 1.1em;
2370 2370 }
2371 2371
2372 2372 #journal .compare_view {
2373 2373 padding: 5px 0px 5px 0px;
2374 2374 width: 95px;
2375 2375 }
2376 2376
2377 2377 .journal_highlight {
2378 2378 font-weight: bold;
2379 2379 padding: 0 2px;
2380 2380 vertical-align: bottom;
2381 2381 }
2382 2382
2383 2383 .trending_language_tbl,.trending_language_tbl td {
2384 2384 border: 0 !important;
2385 2385 margin: 0 !important;
2386 2386 padding: 0 !important;
2387 2387 }
2388 2388
2389 2389 .trending_language_tbl,.trending_language_tbl tr {
2390 2390 border-spacing: 1px;
2391 2391 }
2392 2392
2393 2393 .trending_language {
2394 2394 background-color: #003367;
2395 2395 color: #FFF;
2396 2396 display: block;
2397 2397 min-width: 20px;
2398 2398 text-decoration: none;
2399 2399 height: 12px;
2400 2400 margin-bottom: 0px;
2401 2401 margin-left: 5px;
2402 2402 white-space: pre;
2403 2403 padding: 3px;
2404 2404 }
2405 2405
2406 2406 h3.files_location {
2407 2407 font-size: 1.8em;
2408 2408 font-weight: 700;
2409 2409 border-bottom: none !important;
2410 2410 margin: 10px 0 !important;
2411 2411 }
2412 2412
2413 2413 #files_data dl dt {
2414 2414 float: left;
2415 2415 width: 60px;
2416 2416 margin: 0 !important;
2417 2417 padding: 5px;
2418 2418 }
2419 2419
2420 2420 #files_data dl dd {
2421 2421 margin: 0 !important;
2422 2422 padding: 5px !important;
2423 2423 }
2424 2424
2425 2425 .file_history{
2426 2426 padding-top:10px;
2427 2427 font-size:16px;
2428 2428 }
2429 2429 .file_author{
2430 2430 float: left;
2431 2431 }
2432 2432
2433 2433 .file_author .item{
2434 2434 float:left;
2435 2435 padding:5px;
2436 2436 color: #888;
2437 2437 }
2438 2438
2439 2439 .tablerow0 {
2440 2440 background-color: #F8F8F8;
2441 2441 }
2442 2442
2443 2443 .tablerow1 {
2444 2444 background-color: #FFFFFF;
2445 2445 }
2446 2446
2447 2447 .changeset_id {
2448 2448 font-family: monospace;
2449 2449 color: #666666;
2450 2450 }
2451 2451
2452 2452 .changeset_hash {
2453 2453 color: #000000;
2454 2454 }
2455 2455
2456 2456 #changeset_content {
2457 2457 border-left: 1px solid #CCC;
2458 2458 border-right: 1px solid #CCC;
2459 2459 border-bottom: 1px solid #CCC;
2460 2460 padding: 5px;
2461 2461 }
2462 2462
2463 2463 #changeset_compare_view_content {
2464 2464 border: 1px solid #CCC;
2465 2465 padding: 5px;
2466 2466 }
2467 2467
2468 2468 #changeset_content .container {
2469 2469 min-height: 100px;
2470 2470 font-size: 1.2em;
2471 2471 overflow: hidden;
2472 2472 }
2473 2473
2474 2474 #changeset_compare_view_content .compare_view_commits {
2475 2475 width: auto !important;
2476 2476 }
2477 2477
2478 2478 #changeset_compare_view_content .compare_view_commits td {
2479 2479 padding: 0px 0px 0px 12px !important;
2480 2480 }
2481 2481
2482 2482 #changeset_content .container .right {
2483 2483 float: right;
2484 2484 width: 20%;
2485 2485 text-align: right;
2486 2486 }
2487 2487
2488 2488 #changeset_content .container .left .message {
2489 2489 white-space: pre-wrap;
2490 2490 }
2491 2491 #changeset_content .container .left .message a:hover {
2492 2492 text-decoration: none;
2493 2493 }
2494 2494 .cs_files .cur_cs {
2495 2495 margin: 10px 2px;
2496 2496 font-weight: bold;
2497 2497 }
2498 2498
2499 2499 .cs_files .node {
2500 2500 float: left;
2501 2501 }
2502 2502
2503 2503 .cs_files .changes {
2504 2504 float: right;
2505 2505 color:#003367;
2506 2506
2507 2507 }
2508 2508
2509 2509 .cs_files .changes .added {
2510 2510 background-color: #BBFFBB;
2511 2511 float: left;
2512 2512 text-align: center;
2513 2513 font-size: 9px;
2514 2514 padding: 2px 0px 2px 0px;
2515 2515 }
2516 2516
2517 2517 .cs_files .changes .deleted {
2518 2518 background-color: #FF8888;
2519 2519 float: left;
2520 2520 text-align: center;
2521 2521 font-size: 9px;
2522 2522 padding: 2px 0px 2px 0px;
2523 2523 }
2524 2524 /*new binary*/
2525 2525 .cs_files .changes .bin1 {
2526 2526 background-color: #BBFFBB;
2527 2527 float: left;
2528 2528 text-align: center;
2529 2529 font-size: 9px;
2530 2530 padding: 2px 0px 2px 0px;
2531 2531 }
2532 2532
2533 2533 /*deleted binary*/
2534 2534 .cs_files .changes .bin2 {
2535 2535 background-color: #FF8888;
2536 2536 float: left;
2537 2537 text-align: center;
2538 2538 font-size: 9px;
2539 2539 padding: 2px 0px 2px 0px;
2540 2540 }
2541 2541
2542 2542 /*mod binary*/
2543 2543 .cs_files .changes .bin3 {
2544 2544 background-color: #DDDDDD;
2545 2545 float: left;
2546 2546 text-align: center;
2547 2547 font-size: 9px;
2548 2548 padding: 2px 0px 2px 0px;
2549 2549 }
2550 2550
2551 2551 /*rename file*/
2552 2552 .cs_files .changes .bin4 {
2553 2553 background-color: #6D99FF;
2554 2554 float: left;
2555 2555 text-align: center;
2556 2556 font-size: 9px;
2557 2557 padding: 2px 0px 2px 0px;
2558 2558 }
2559 2559
2560 2560
2561 2561 .cs_files .cs_added,.cs_files .cs_A {
2562 2562 background: url("../images/icons/page_white_add.png") no-repeat scroll
2563 2563 3px;
2564 2564 height: 16px;
2565 2565 padding-left: 20px;
2566 2566 margin-top: 7px;
2567 2567 text-align: left;
2568 2568 }
2569 2569
2570 2570 .cs_files .cs_changed,.cs_files .cs_M {
2571 2571 background: url("../images/icons/page_white_edit.png") no-repeat scroll
2572 2572 3px;
2573 2573 height: 16px;
2574 2574 padding-left: 20px;
2575 2575 margin-top: 7px;
2576 2576 text-align: left;
2577 2577 }
2578 2578
2579 2579 .cs_files .cs_removed,.cs_files .cs_D {
2580 2580 background: url("../images/icons/page_white_delete.png") no-repeat
2581 2581 scroll 3px;
2582 2582 height: 16px;
2583 2583 padding-left: 20px;
2584 2584 margin-top: 7px;
2585 2585 text-align: left;
2586 2586 }
2587 2587
2588 2588 #graph {
2589 2589 overflow: hidden;
2590 2590 }
2591 2591
2592 2592 #graph_nodes {
2593 2593 float: left;
2594 2594 margin-right: 0px;
2595 2595 margin-top: 0px;
2596 2596 }
2597 2597
2598 2598 #graph_content {
2599 2599 width: 80%;
2600 2600 float: left;
2601 2601 }
2602 2602
2603 2603 #graph_content .container_header {
2604 2604 border-bottom: 1px solid #DDD;
2605 2605 padding: 10px;
2606 2606 height: 25px;
2607 2607 }
2608 2608
2609 2609 #graph_content #rev_range_container {
2610 2610 float: left;
2611 2611 margin: 0px 0px 0px 3px;
2612 2612 }
2613 2613
2614 2614 #graph_content #rev_range_clear {
2615 2615 float: left;
2616 2616 margin: 0px 0px 0px 3px;
2617 2617 }
2618 2618
2619 2619 #graph_content .container {
2620 2620 border-bottom: 1px solid #DDD;
2621 2621 height: 56px;
2622 2622 overflow: hidden;
2623 2623 }
2624 2624
2625 2625 #graph_content .container .right {
2626 2626 float: right;
2627 2627 width: 23%;
2628 2628 text-align: right;
2629 2629 }
2630 2630
2631 2631 #graph_content .container .left {
2632 2632 float: left;
2633 2633 width: 25%;
2634 2634 padding-left: 5px;
2635 2635 }
2636 2636
2637 2637 #graph_content .container .mid {
2638 2638 float: left;
2639 2639 width: 49%;
2640 2640 }
2641 2641
2642 2642
2643 2643 #graph_content .container .left .date {
2644 2644 color: #666;
2645 2645 padding-left: 22px;
2646 2646 font-size: 10px;
2647 2647 }
2648 2648
2649 2649 #graph_content .container .left .author {
2650 2650 height: 22px;
2651 2651 }
2652 2652
2653 2653 #graph_content .container .left .author .user {
2654 2654 color: #444444;
2655 2655 float: left;
2656 2656 margin-left: -4px;
2657 2657 margin-top: 4px;
2658 2658 }
2659 2659
2660 2660 #graph_content .container .mid .message {
2661 2661 white-space: pre-wrap;
2662 2662 }
2663 2663
2664 2664 #graph_content .container .mid .message a:hover{
2665 2665 text-decoration: none;
2666 2666 }
2667 2667
2668 2668 .revision-link
2669 2669 {
2670 2670 color:#3F6F9F;
2671 2671 font-weight: bold !important;
2672 2672 }
2673 2673
2674 2674 .issue-tracker-link{
2675 2675 color:#3F6F9F;
2676 2676 font-weight: bold !important;
2677 2677 }
2678 2678
2679 2679 .changeset-status-container{
2680 2680 padding-right: 5px;
2681 2681 margin-top:1px;
2682 2682 float:right;
2683 2683 height:14px;
2684 2684 }
2685 2685 .code-header .changeset-status-container{
2686 2686 float:left;
2687 2687 padding:2px 0px 0px 2px;
2688 2688 }
2689 2689 .changeset-status-container .changeset-status-lbl{
2690 2690 color: rgb(136, 136, 136);
2691 2691 float: left;
2692 2692 padding: 3px 4px 0px 0px
2693 2693 }
2694 2694 .code-header .changeset-status-container .changeset-status-lbl{
2695 2695 float: left;
2696 2696 padding: 0px 4px 0px 0px;
2697 2697 }
2698 2698 .changeset-status-container .changeset-status-ico{
2699 2699 float: left;
2700 2700 }
2701 2701 .code-header .changeset-status-container .changeset-status-ico, .container .changeset-status-ico{
2702 2702 float: left;
2703 2703 }
2704 2704 .right .comments-container{
2705 2705 padding-right: 5px;
2706 2706 margin-top:1px;
2707 2707 float:right;
2708 2708 height:14px;
2709 2709 }
2710 2710
2711 2711 .right .comments-cnt{
2712 2712 float: left;
2713 2713 color: rgb(136, 136, 136);
2714 2714 padding-right: 2px;
2715 2715 }
2716 2716
2717 2717 .right .changes{
2718 2718 clear: both;
2719 2719 }
2720 2720
2721 2721 .right .changes .changed_total {
2722 2722 display: block;
2723 2723 float: right;
2724 2724 text-align: center;
2725 2725 min-width: 45px;
2726 2726 cursor: pointer;
2727 2727 color: #444444;
2728 2728 background: #FEA;
2729 2729 -webkit-border-radius: 0px 0px 0px 6px;
2730 2730 -moz-border-radius: 0px 0px 0px 6px;
2731 2731 border-radius: 0px 0px 0px 6px;
2732 2732 padding: 1px;
2733 2733 }
2734 2734
2735 2735 .right .changes .added,.changed,.removed {
2736 2736 display: block;
2737 2737 padding: 1px;
2738 2738 color: #444444;
2739 2739 float: right;
2740 2740 text-align: center;
2741 2741 min-width: 15px;
2742 2742 }
2743 2743
2744 2744 .right .changes .added {
2745 2745 background: #CFC;
2746 2746 }
2747 2747
2748 2748 .right .changes .changed {
2749 2749 background: #FEA;
2750 2750 }
2751 2751
2752 2752 .right .changes .removed {
2753 2753 background: #FAA;
2754 2754 }
2755 2755
2756 2756 .right .merge {
2757 2757 padding: 1px 3px 1px 3px;
2758 2758 background-color: #fca062;
2759 2759 font-size: 10px;
2760 2760 font-weight: bold;
2761 2761 color: #ffffff;
2762 2762 text-transform: uppercase;
2763 2763 white-space: nowrap;
2764 2764 -webkit-border-radius: 3px;
2765 2765 -moz-border-radius: 3px;
2766 2766 border-radius: 3px;
2767 2767 margin-right: 2px;
2768 2768 }
2769 2769
2770 2770 .right .parent {
2771 2771 color: #666666;
2772 2772 clear:both;
2773 2773 }
2774 2774 .right .logtags{
2775 2775 padding: 2px 2px 2px 2px;
2776 2776 }
2777 2777 .right .logtags .branchtag,.right .logtags .tagtag,.right .logtags .booktag{
2778 2778 margin: 0px 2px;
2779 2779 }
2780 2780
2781 2781 .right .logtags .branchtag,.logtags .branchtag {
2782 2782 padding: 1px 3px 1px 3px;
2783 2783 background-color: #bfbfbf;
2784 2784 font-size: 10px;
2785 2785 font-weight: bold;
2786 2786 color: #ffffff;
2787 2787 text-transform: uppercase;
2788 2788 white-space: nowrap;
2789 2789 -webkit-border-radius: 3px;
2790 2790 -moz-border-radius: 3px;
2791 2791 border-radius: 3px;
2792 2792 }
2793 2793 .right .logtags .branchtag a:hover,.logtags .branchtag a{
2794 2794 color: #ffffff;
2795 2795 }
2796 2796 .right .logtags .branchtag a:hover,.logtags .branchtag a:hover{
2797 2797 text-decoration: none;
2798 2798 color: #ffffff;
2799 2799 }
2800 2800 .right .logtags .tagtag,.logtags .tagtag {
2801 2801 padding: 1px 3px 1px 3px;
2802 2802 background-color: #62cffc;
2803 2803 font-size: 10px;
2804 2804 font-weight: bold;
2805 2805 color: #ffffff;
2806 2806 text-transform: uppercase;
2807 2807 white-space: nowrap;
2808 2808 -webkit-border-radius: 3px;
2809 2809 -moz-border-radius: 3px;
2810 2810 border-radius: 3px;
2811 2811 }
2812 2812 .right .logtags .tagtag a:hover,.logtags .tagtag a{
2813 2813 color: #ffffff;
2814 2814 }
2815 2815 .right .logtags .tagtag a:hover,.logtags .tagtag a:hover{
2816 2816 text-decoration: none;
2817 2817 color: #ffffff;
2818 2818 }
2819 2819 .right .logbooks .bookbook,.logbooks .bookbook,.right .logtags .bookbook,.logtags .bookbook {
2820 2820 padding: 1px 3px 1px 3px;
2821 2821 background-color: #46A546;
2822 2822 font-size: 10px;
2823 2823 font-weight: bold;
2824 2824 color: #ffffff;
2825 2825 text-transform: uppercase;
2826 2826 white-space: nowrap;
2827 2827 -webkit-border-radius: 3px;
2828 2828 -moz-border-radius: 3px;
2829 2829 border-radius: 3px;
2830 2830 }
2831 2831 .right .logbooks .bookbook,.logbooks .bookbook a,.right .logtags .bookbook,.logtags .bookbook a{
2832 2832 color: #ffffff;
2833 2833 }
2834 2834 .right .logbooks .bookbook,.logbooks .bookbook a:hover,.right .logtags .bookbook,.logtags .bookbook a:hover{
2835 2835 text-decoration: none;
2836 2836 color: #ffffff;
2837 2837 }
2838 2838 div.browserblock {
2839 2839 overflow: hidden;
2840 2840 border: 1px solid #ccc;
2841 2841 background: #f8f8f8;
2842 2842 font-size: 100%;
2843 2843 line-height: 125%;
2844 2844 padding: 0;
2845 2845 -webkit-border-radius: 6px 6px 0px 0px;
2846 2846 -moz-border-radius: 6px 6px 0px 0px;
2847 2847 border-radius: 6px 6px 0px 0px;
2848 2848 }
2849 2849
2850 2850 div.browserblock .browser-header {
2851 2851 background: #FFF;
2852 2852 padding: 10px 0px 15px 0px;
2853 2853 width: 100%;
2854 2854 }
2855 2855
2856 2856 div.browserblock .browser-nav {
2857 2857 float: left
2858 2858 }
2859 2859
2860 2860 div.browserblock .browser-branch {
2861 2861 float: left;
2862 2862 }
2863 2863
2864 2864 div.browserblock .browser-branch label {
2865 2865 color: #4A4A4A;
2866 2866 vertical-align: text-top;
2867 2867 }
2868 2868
2869 2869 div.browserblock .browser-header span {
2870 2870 margin-left: 5px;
2871 2871 font-weight: 700;
2872 2872 }
2873 2873
2874 2874 div.browserblock .browser-search {
2875 2875 clear: both;
2876 2876 padding: 8px 8px 0px 5px;
2877 2877 height: 20px;
2878 2878 }
2879 2879
2880 2880 div.browserblock #node_filter_box {
2881 2881
2882 2882 }
2883 2883
2884 2884 div.browserblock .search_activate {
2885 2885 float: left
2886 2886 }
2887 2887
2888 2888 div.browserblock .add_node {
2889 2889 float: left;
2890 2890 padding-left: 5px;
2891 2891 }
2892 2892
2893 2893 div.browserblock .search_activate a:hover,div.browserblock .add_node a:hover
2894 2894 {
2895 2895 text-decoration: none !important;
2896 2896 }
2897 2897
2898 2898 div.browserblock .browser-body {
2899 2899 background: #EEE;
2900 2900 border-top: 1px solid #CCC;
2901 2901 }
2902 2902
2903 2903 table.code-browser {
2904 2904 border-collapse: collapse;
2905 2905 width: 100%;
2906 2906 }
2907 2907
2908 2908 table.code-browser tr {
2909 2909 margin: 3px;
2910 2910 }
2911 2911
2912 2912 table.code-browser thead th {
2913 2913 background-color: #EEE;
2914 2914 height: 20px;
2915 2915 font-size: 1.1em;
2916 2916 font-weight: 700;
2917 2917 text-align: left;
2918 2918 padding-left: 10px;
2919 2919 }
2920 2920
2921 2921 table.code-browser tbody td {
2922 2922 padding-left: 10px;
2923 2923 height: 20px;
2924 2924 }
2925 2925
2926 2926 table.code-browser .browser-file {
2927 2927 background: url("../images/icons/document_16.png") no-repeat scroll 3px;
2928 2928 height: 16px;
2929 2929 padding-left: 20px;
2930 2930 text-align: left;
2931 2931 }
2932 2932 .diffblock .changeset_header {
2933 2933 height: 16px;
2934 2934 }
2935 2935 .diffblock .changeset_file {
2936 2936 background: url("../images/icons/file.png") no-repeat scroll 3px;
2937 2937 text-align: left;
2938 2938 float: left;
2939 2939 padding: 2px 0px 2px 22px;
2940 2940 }
2941 2941 .diffblock .diff-menu-wrapper{
2942 2942 float: left;
2943 2943 }
2944 2944
2945 2945 .diffblock .diff-menu{
2946 2946 position: absolute;
2947 2947 background: none repeat scroll 0 0 #FFFFFF;
2948 2948 border-color: #003367 #666666 #666666;
2949 2949 border-right: 1px solid #666666;
2950 2950 border-style: solid solid solid;
2951 2951 border-width: 1px;
2952 2952 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
2953 2953 margin-top:5px;
2954 2954 margin-left:1px;
2955 2955
2956 2956 }
2957 2957 .diffblock .diff-actions {
2958 2958 padding: 2px 0px 0px 2px;
2959 2959 float: left;
2960 2960 }
2961 2961 .diffblock .diff-menu ul li {
2962 2962 padding: 0px 0px 0px 0px !important;
2963 2963 }
2964 2964 .diffblock .diff-menu ul li a{
2965 2965 display: block;
2966 2966 padding: 3px 8px 3px 8px !important;
2967 2967 }
2968 2968 .diffblock .diff-menu ul li a:hover{
2969 2969 text-decoration: none;
2970 2970 background-color: #EEEEEE;
2971 2971 }
2972 2972 table.code-browser .browser-dir {
2973 2973 background: url("../images/icons/folder_16.png") no-repeat scroll 3px;
2974 2974 height: 16px;
2975 2975 padding-left: 20px;
2976 2976 text-align: left;
2977 2977 }
2978 2978
2979 2979 table.code-browser .submodule-dir {
2980 2980 background: url("../images/icons/disconnect.png") no-repeat scroll 3px;
2981 2981 height: 16px;
2982 2982 padding-left: 20px;
2983 2983 text-align: left;
2984 2984 }
2985 2985
2986 2986
2987 2987 .box .search {
2988 2988 clear: both;
2989 2989 overflow: hidden;
2990 2990 margin: 0;
2991 2991 padding: 0 20px 10px;
2992 2992 }
2993 2993
2994 2994 .box .search div.search_path {
2995 2995 background: none repeat scroll 0 0 #EEE;
2996 2996 border: 1px solid #CCC;
2997 2997 color: blue;
2998 2998 margin-bottom: 10px;
2999 2999 padding: 10px 0;
3000 3000 }
3001 3001
3002 3002 .box .search div.search_path div.link {
3003 3003 font-weight: 700;
3004 3004 margin-left: 25px;
3005 3005 }
3006 3006
3007 3007 .box .search div.search_path div.link a {
3008 3008 color: #003367;
3009 3009 cursor: pointer;
3010 3010 text-decoration: none;
3011 3011 }
3012 3012
3013 3013 #path_unlock {
3014 3014 color: red;
3015 3015 font-size: 1.2em;
3016 3016 padding-left: 4px;
3017 3017 }
3018 3018
3019 3019 .info_box span {
3020 3020 margin-left: 3px;
3021 3021 margin-right: 3px;
3022 3022 }
3023 3023
3024 3024 .info_box .rev {
3025 3025 color: #003367;
3026 3026 font-size: 1.6em;
3027 3027 font-weight: bold;
3028 3028 vertical-align: sub;
3029 3029 }
3030 3030
3031 3031 .info_box input#at_rev,.info_box input#size {
3032 3032 background: #FFF;
3033 3033 border-top: 1px solid #b3b3b3;
3034 3034 border-left: 1px solid #b3b3b3;
3035 3035 border-right: 1px solid #eaeaea;
3036 3036 border-bottom: 1px solid #eaeaea;
3037 3037 color: #000;
3038 3038 font-size: 12px;
3039 3039 margin: 0;
3040 3040 padding: 1px 5px 1px;
3041 3041 }
3042 3042
3043 3043 .info_box input#view {
3044 3044 text-align: center;
3045 3045 padding: 4px 3px 2px 2px;
3046 3046 }
3047 3047
3048 3048 .yui-overlay,.yui-panel-container {
3049 3049 visibility: hidden;
3050 3050 position: absolute;
3051 3051 z-index: 2;
3052 3052 }
3053 3053
3054 3054 #tip-box {
3055 3055 position: absolute;
3056 3056
3057 3057 background-color: #FFF;
3058 3058 border: 2px solid #003367;
3059 3059 font: 100% sans-serif;
3060 3060 width: auto;
3061 3061 opacity: 1px;
3062 3062 padding: 8px;
3063 3063
3064 3064 white-space: pre-wrap;
3065 3065 -webkit-border-radius: 8px 8px 8px 8px;
3066 3066 -khtml-border-radius: 8px 8px 8px 8px;
3067 3067 -moz-border-radius: 8px 8px 8px 8px;
3068 3068 border-radius: 8px 8px 8px 8px;
3069 3069 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3070 3070 -moz-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3071 3071 -webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3072 3072 }
3073 3073
3074 3074 .hl-tip-box {
3075 3075 visibility: hidden;
3076 3076 position: absolute;
3077 3077 color: #666;
3078 3078 background-color: #FFF;
3079 3079 border: 2px solid #003367;
3080 3080 font: 100% sans-serif;
3081 3081 width: auto;
3082 3082 opacity: 1px;
3083 3083 padding: 8px;
3084 3084 white-space: pre-wrap;
3085 3085 -webkit-border-radius: 8px 8px 8px 8px;
3086 3086 -khtml-border-radius: 8px 8px 8px 8px;
3087 3087 -moz-border-radius: 8px 8px 8px 8px;
3088 3088 border-radius: 8px 8px 8px 8px;
3089 3089 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3090 3090 }
3091 3091
3092 3092
3093 3093 .mentions-container{
3094 3094 width: 90% !important;
3095 3095 }
3096 3096 .mentions-container .yui-ac-content{
3097 3097 width: 100% !important;
3098 3098 }
3099 3099
3100 3100 .ac {
3101 3101 vertical-align: top;
3102 3102 }
3103 3103
3104 3104 .ac .yui-ac {
3105 3105 position: inherit;
3106 3106 font-size: 100%;
3107 3107 }
3108 3108
3109 3109 .ac .perm_ac {
3110 3110 width: 20em;
3111 3111 }
3112 3112
3113 3113 .ac .yui-ac-input {
3114 3114 width: 100%;
3115 3115 }
3116 3116
3117 3117 .ac .yui-ac-container {
3118 3118 position: absolute;
3119 3119 top: 1.6em;
3120 3120 width: auto;
3121 3121 }
3122 3122
3123 3123 .ac .yui-ac-content {
3124 3124 position: absolute;
3125 3125 border: 1px solid gray;
3126 3126 background: #fff;
3127 3127 z-index: 9050;
3128 3128
3129 3129 }
3130 3130
3131 3131 .ac .yui-ac-shadow {
3132 3132 position: absolute;
3133 3133 width: 100%;
3134 3134 background: #000;
3135 3135 -moz-opacity: 0.1px;
3136 3136 opacity: .10;
3137 3137 filter: alpha(opacity = 10);
3138 3138 z-index: 9049;
3139 3139 margin: .3em;
3140 3140 }
3141 3141
3142 3142 .ac .yui-ac-content ul {
3143 3143 width: 100%;
3144 3144 margin: 0;
3145 3145 padding: 0;
3146 3146 z-index: 9050;
3147 3147 }
3148 3148
3149 3149 .ac .yui-ac-content li {
3150 3150 cursor: default;
3151 3151 white-space: nowrap;
3152 3152 margin: 0;
3153 3153 padding: 2px 5px;
3154 3154 height: 18px;
3155 3155 z-index: 9050;
3156 3156 display: block;
3157 3157 width: auto !important;
3158 3158 }
3159 3159
3160 3160 .ac .yui-ac-content li .ac-container-wrap{
3161 3161 width: auto;
3162 3162 }
3163 3163
3164 3164 .ac .yui-ac-content li.yui-ac-prehighlight {
3165 3165 background: #B3D4FF;
3166 3166 z-index: 9050;
3167 3167 }
3168 3168
3169 3169 .ac .yui-ac-content li.yui-ac-highlight {
3170 3170 background: #556CB5;
3171 3171 color: #FFF;
3172 3172 z-index: 9050;
3173 3173 }
3174 3174 .ac .yui-ac-bd{
3175 3175 z-index: 9050;
3176 3176 }
3177 3177
3178 3178 .follow {
3179 3179 background: url("../images/icons/heart_add.png") no-repeat scroll 3px;
3180 3180 height: 16px;
3181 3181 width: 20px;
3182 3182 cursor: pointer;
3183 3183 display: block;
3184 3184 float: right;
3185 3185 margin-top: 2px;
3186 3186 }
3187 3187
3188 3188 .following {
3189 3189 background: url("../images/icons/heart_delete.png") no-repeat scroll 3px;
3190 3190 height: 16px;
3191 3191 width: 20px;
3192 3192 cursor: pointer;
3193 3193 display: block;
3194 3194 float: right;
3195 3195 margin-top: 2px;
3196 3196 }
3197 3197
3198 3198 .locking_locked{
3199 3199 background: #FFF url("../images/icons/block_16.png") no-repeat scroll 3px;
3200 3200 height: 16px;
3201 3201 width: 20px;
3202 3202 cursor: pointer;
3203 3203 display: block;
3204 3204 float: right;
3205 3205 margin-top: 2px;
3206 3206 }
3207 3207
3208 3208 .locking_unlocked{
3209 3209 background: #FFF url("../images/icons/accept.png") no-repeat scroll 3px;
3210 3210 height: 16px;
3211 3211 width: 20px;
3212 3212 cursor: pointer;
3213 3213 display: block;
3214 3214 float: right;
3215 3215 margin-top: 2px;
3216 3216 }
3217 3217
3218 3218 .currently_following {
3219 3219 padding-left: 10px;
3220 3220 padding-bottom: 5px;
3221 3221 }
3222 3222
3223 3223 .add_icon {
3224 3224 background: url("../images/icons/add.png") no-repeat scroll 3px;
3225 3225 padding-left: 20px;
3226 3226 padding-top: 0px;
3227 3227 text-align: left;
3228 3228 }
3229 3229
3230 3230 .accept_icon {
3231 3231 background: url("../images/icons/accept.png") no-repeat scroll 3px;
3232 3232 padding-left: 20px;
3233 3233 padding-top: 0px;
3234 3234 text-align: left;
3235 3235 }
3236 3236
3237 3237 .edit_icon {
3238 background: url("../images/icons/folder_edit.png") no-repeat scroll 3px;
3238 background: url("../images/icons/application_form_edit.png") no-repeat scroll 3px;
3239 3239 padding-left: 20px;
3240 3240 padding-top: 0px;
3241 3241 text-align: left;
3242 3242 }
3243 3243
3244 3244 .delete_icon {
3245 3245 background: url("../images/icons/delete.png") no-repeat scroll 3px;
3246 3246 padding-left: 20px;
3247 3247 padding-top: 0px;
3248 3248 text-align: left;
3249 3249 }
3250 3250
3251 3251 .refresh_icon {
3252 3252 background: url("../images/icons/arrow_refresh.png") no-repeat scroll
3253 3253 3px;
3254 3254 padding-left: 20px;
3255 3255 padding-top: 0px;
3256 3256 text-align: left;
3257 3257 }
3258 3258
3259 3259 .pull_icon {
3260 3260 background: url("../images/icons/connect.png") no-repeat scroll 3px;
3261 3261 padding-left: 20px;
3262 3262 padding-top: 0px;
3263 3263 text-align: left;
3264 3264 }
3265 3265
3266 3266 .rss_icon {
3267 3267 background: url("../images/icons/rss_16.png") no-repeat scroll 3px;
3268 3268 padding-left: 20px;
3269 3269 padding-top: 4px;
3270 3270 text-align: left;
3271 3271 font-size: 8px
3272 3272 }
3273 3273
3274 3274 .atom_icon {
3275 3275 background: url("../images/icons/atom.png") no-repeat scroll 3px;
3276 3276 padding-left: 20px;
3277 3277 padding-top: 4px;
3278 3278 text-align: left;
3279 3279 font-size: 8px
3280 3280 }
3281 3281
3282 3282 .archive_icon {
3283 3283 background: url("../images/icons/compress.png") no-repeat scroll 3px;
3284 3284 padding-left: 20px;
3285 3285 text-align: left;
3286 3286 padding-top: 1px;
3287 3287 }
3288 3288
3289 3289 .start_following_icon {
3290 3290 background: url("../images/icons/heart_add.png") no-repeat scroll 3px;
3291 3291 padding-left: 20px;
3292 3292 text-align: left;
3293 3293 padding-top: 0px;
3294 3294 }
3295 3295
3296 3296 .stop_following_icon {
3297 3297 background: url("../images/icons/heart_delete.png") no-repeat scroll 3px;
3298 3298 padding-left: 20px;
3299 3299 text-align: left;
3300 3300 padding-top: 0px;
3301 3301 }
3302 3302
3303 3303 .action_button {
3304 3304 border: 0;
3305 3305 display: inline;
3306 3306 }
3307 3307
3308 3308 .action_button:hover {
3309 3309 border: 0;
3310 3310 text-decoration: underline;
3311 3311 cursor: pointer;
3312 3312 }
3313 3313
3314 3314 #switch_repos {
3315 3315 position: absolute;
3316 3316 height: 25px;
3317 3317 z-index: 1;
3318 3318 }
3319 3319
3320 3320 #switch_repos select {
3321 3321 min-width: 150px;
3322 3322 max-height: 250px;
3323 3323 z-index: 1;
3324 3324 }
3325 3325
3326 3326 .breadcrumbs {
3327 3327 border: medium none;
3328 3328 color: #FFF;
3329 3329 float: left;
3330 3330 text-transform: uppercase;
3331 3331 font-weight: 700;
3332 3332 font-size: 14px;
3333 3333 margin: 0;
3334 3334 padding: 11px 0 11px 10px;
3335 3335 }
3336 3336
3337 3337 .breadcrumbs .hash {
3338 3338 text-transform: none;
3339 3339 color: #fff;
3340 3340 }
3341 3341
3342 3342 .breadcrumbs a {
3343 3343 color: #FFF;
3344 3344 }
3345 3345
3346 3346 .flash_msg {
3347 3347
3348 3348 }
3349 3349
3350 3350 .flash_msg ul {
3351 3351
3352 3352 }
3353 3353
3354 3354 .error_red {
3355 3355 color:red;
3356 3356 }
3357 3357
3358 3358 .error_msg {
3359 3359 background-color: #c43c35;
3360 3360 background-repeat: repeat-x;
3361 3361 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35) );
3362 3362 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3363 3363 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3364 3364 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35) );
3365 3365 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3366 3366 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3367 3367 background-image: linear-gradient(top, #ee5f5b, #c43c35);
3368 3368 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#c43c35', GradientType=0 );
3369 3369 border-color: #c43c35 #c43c35 #882a25;
3370 3370 }
3371 3371
3372 3372 .warning_msg {
3373 3373 color: #404040 !important;
3374 3374 background-color: #eedc94;
3375 3375 background-repeat: repeat-x;
3376 3376 background-image: -khtml-gradient(linear, left top, left bottom, from(#fceec1), to(#eedc94) );
3377 3377 background-image: -moz-linear-gradient(top, #fceec1, #eedc94);
3378 3378 background-image: -ms-linear-gradient(top, #fceec1, #eedc94);
3379 3379 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94) );
3380 3380 background-image: -webkit-linear-gradient(top, #fceec1, #eedc94);
3381 3381 background-image: -o-linear-gradient(top, #fceec1, #eedc94);
3382 3382 background-image: linear-gradient(top, #fceec1, #eedc94);
3383 3383 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1', endColorstr='#eedc94', GradientType=0 );
3384 3384 border-color: #eedc94 #eedc94 #e4c652;
3385 3385 }
3386 3386
3387 3387 .success_msg {
3388 3388 background-color: #57a957;
3389 3389 background-repeat: repeat-x !important;
3390 3390 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957) );
3391 3391 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3392 3392 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3393 3393 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957) );
3394 3394 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3395 3395 background-image: -o-linear-gradient(top, #62c462, #57a957);
3396 3396 background-image: linear-gradient(top, #62c462, #57a957);
3397 3397 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0 );
3398 3398 border-color: #57a957 #57a957 #3d773d;
3399 3399 }
3400 3400
3401 3401 .notice_msg {
3402 3402 background-color: #339bb9;
3403 3403 background-repeat: repeat-x;
3404 3404 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9) );
3405 3405 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3406 3406 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3407 3407 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9) );
3408 3408 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3409 3409 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3410 3410 background-image: linear-gradient(top, #5bc0de, #339bb9);
3411 3411 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0 );
3412 3412 border-color: #339bb9 #339bb9 #22697d;
3413 3413 }
3414 3414
3415 3415 .success_msg,.error_msg,.notice_msg,.warning_msg {
3416 3416 font-size: 12px;
3417 3417 font-weight: 700;
3418 3418 min-height: 14px;
3419 3419 line-height: 14px;
3420 3420 margin-bottom: 10px;
3421 3421 margin-top: 0;
3422 3422 display: block;
3423 3423 overflow: auto;
3424 3424 padding: 6px 10px 6px 10px;
3425 3425 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3426 3426 position: relative;
3427 3427 color: #FFF;
3428 3428 border-width: 1px;
3429 3429 border-style: solid;
3430 3430 -webkit-border-radius: 4px;
3431 3431 -moz-border-radius: 4px;
3432 3432 border-radius: 4px;
3433 3433 -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3434 3434 -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3435 3435 box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3436 3436 }
3437 3437
3438 3438 #msg_close {
3439 3439 background: transparent url("../icons/cross_grey_small.png") no-repeat scroll 0 0;
3440 3440 cursor: pointer;
3441 3441 height: 16px;
3442 3442 position: absolute;
3443 3443 right: 5px;
3444 3444 top: 5px;
3445 3445 width: 16px;
3446 3446 }
3447 3447 div#legend_data{
3448 3448 padding-left:10px;
3449 3449 }
3450 3450 div#legend_container table{
3451 3451 border: none !important;
3452 3452 }
3453 3453 div#legend_container table,div#legend_choices table {
3454 3454 width: auto !important;
3455 3455 }
3456 3456
3457 3457 table#permissions_manage {
3458 3458 width: 0 !important;
3459 3459 }
3460 3460
3461 3461 table#permissions_manage span.private_repo_msg {
3462 3462 font-size: 0.8em;
3463 3463 opacity: 0.6px;
3464 3464 }
3465 3465
3466 3466 table#permissions_manage td.private_repo_msg {
3467 3467 font-size: 0.8em;
3468 3468 }
3469 3469
3470 3470 table#permissions_manage tr#add_perm_input td {
3471 3471 vertical-align: middle;
3472 3472 }
3473 3473
3474 3474 div.gravatar {
3475 3475 background-color: #FFF;
3476 3476 float: left;
3477 3477 margin-right: 0.7em;
3478 3478 padding: 1px 1px 1px 1px;
3479 3479 line-height:0;
3480 3480 -webkit-border-radius: 3px;
3481 3481 -khtml-border-radius: 3px;
3482 3482 -moz-border-radius: 3px;
3483 3483 border-radius: 3px;
3484 3484 }
3485 3485
3486 3486 div.gravatar img {
3487 3487 -webkit-border-radius: 2px;
3488 3488 -khtml-border-radius: 2px;
3489 3489 -moz-border-radius: 2px;
3490 3490 border-radius: 2px;
3491 3491 }
3492 3492
3493 3493 #header,#content,#footer {
3494 3494 min-width: 978px;
3495 3495 }
3496 3496
3497 3497 #content {
3498 3498 clear: both;
3499 3499 overflow: hidden;
3500 3500 padding: 54px 10px 14px 10px;
3501 3501 }
3502 3502
3503 3503 #content div.box div.title div.search {
3504 3504
3505 3505 border-left: 1px solid #316293;
3506 3506 }
3507 3507
3508 3508 #content div.box div.title div.search div.input input {
3509 3509 border: 1px solid #316293;
3510 3510 }
3511 3511
3512 3512 .ui-btn{
3513 3513 color: #515151;
3514 3514 background-color: #DADADA;
3515 3515 background-repeat: repeat-x;
3516 3516 background-image: -khtml-gradient(linear, left top, left bottom, from(#F4F4F4),to(#DADADA) );
3517 3517 background-image: -moz-linear-gradient(top, #F4F4F4, #DADADA);
3518 3518 background-image: -ms-linear-gradient(top, #F4F4F4, #DADADA);
3519 3519 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #F4F4F4),color-stop(100%, #DADADA) );
3520 3520 background-image: -webkit-linear-gradient(top, #F4F4F4, #DADADA) );
3521 3521 background-image: -o-linear-gradient(top, #F4F4F4, #DADADA) );
3522 3522 background-image: linear-gradient(top, #F4F4F4, #DADADA);
3523 3523 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F4F4F4', endColorstr='#DADADA', GradientType=0);
3524 3524
3525 3525 border-top: 1px solid #DDD;
3526 3526 border-left: 1px solid #c6c6c6;
3527 3527 border-right: 1px solid #DDD;
3528 3528 border-bottom: 1px solid #c6c6c6;
3529 3529 color: #515151;
3530 3530 outline: none;
3531 3531 margin: 0px 3px 3px 0px;
3532 3532 -webkit-border-radius: 4px 4px 4px 4px !important;
3533 3533 -khtml-border-radius: 4px 4px 4px 4px !important;
3534 3534 -moz-border-radius: 4px 4px 4px 4px !important;
3535 3535 border-radius: 4px 4px 4px 4px !important;
3536 3536 cursor: pointer !important;
3537 3537 padding: 3px 3px 3px 3px;
3538 3538 background-position: 0 -15px;
3539 3539
3540 3540 }
3541 3541 .ui-btn.xsmall{
3542 3542 padding: 1px 2px 1px 1px;
3543 3543 }
3544 3544
3545 3545 .ui-btn.large{
3546 3546 padding: 6px 12px;
3547 3547 }
3548 3548
3549 3549 .ui-btn.clone{
3550 3550 padding: 5px 2px 6px 1px;
3551 3551 margin: 0px -4px 3px 0px;
3552 3552 -webkit-border-radius: 4px 0px 0px 4px !important;
3553 3553 -khtml-border-radius: 4px 0px 0px 4px !important;
3554 3554 -moz-border-radius: 4px 0px 0px 4px !important;
3555 3555 border-radius: 4px 0px 0px 4px !important;
3556 3556 width: 100px;
3557 3557 text-align: center;
3558 3558 float: left;
3559 3559 position: absolute;
3560 3560 }
3561 3561 .ui-btn:focus {
3562 3562 outline: none;
3563 3563 }
3564 3564 .ui-btn:hover{
3565 3565 background-position: 0 0px;
3566 3566 text-decoration: none;
3567 3567 color: #515151;
3568 3568 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), 0 0 3px #FFFFFF !important;
3569 3569 }
3570 3570
3571 3571 .ui-btn.red{
3572 3572 color:#fff;
3573 3573 background-color: #c43c35;
3574 3574 background-repeat: repeat-x;
3575 3575 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));
3576 3576 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3577 3577 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3578 3578 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35));
3579 3579 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3580 3580 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3581 3581 background-image: linear-gradient(top, #ee5f5b, #c43c35);
3582 3582 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);
3583 3583 border-color: #c43c35 #c43c35 #882a25;
3584 3584 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3585 3585 }
3586 3586
3587 3587
3588 3588 .ui-btn.blue{
3589 3589 color:#fff;
3590 3590 background-color: #339bb9;
3591 3591 background-repeat: repeat-x;
3592 3592 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9));
3593 3593 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3594 3594 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3595 3595 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9));
3596 3596 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3597 3597 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3598 3598 background-image: linear-gradient(top, #5bc0de, #339bb9);
3599 3599 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);
3600 3600 border-color: #339bb9 #339bb9 #22697d;
3601 3601 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3602 3602 }
3603 3603
3604 3604 .ui-btn.green{
3605 3605 background-color: #57a957;
3606 3606 background-repeat: repeat-x;
3607 3607 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957));
3608 3608 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3609 3609 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3610 3610 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957));
3611 3611 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3612 3612 background-image: -o-linear-gradient(top, #62c462, #57a957);
3613 3613 background-image: linear-gradient(top, #62c462, #57a957);
3614 3614 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);
3615 3615 border-color: #57a957 #57a957 #3d773d;
3616 3616 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3617 3617 }
3618 3618
3619 3619 .ui-btn.blue.hidden{
3620 3620 display: none;
3621 3621 }
3622 3622
3623 3623 .ui-btn.active{
3624 3624 font-weight: bold;
3625 3625 }
3626 3626
3627 3627 ins,div.options a:hover {
3628 3628 text-decoration: none;
3629 3629 }
3630 3630
3631 3631 img,
3632 3632 #header #header-inner #quick li a:hover span.normal,
3633 3633 #header #header-inner #quick li ul li.last,
3634 3634 #content div.box div.form div.fields div.field div.textarea table td table td a,
3635 3635 #clone_url,
3636 3636 #clone_url_id
3637 3637 {
3638 3638 border: none;
3639 3639 }
3640 3640
3641 3641 img.icon,.right .merge img {
3642 3642 vertical-align: bottom;
3643 3643 }
3644 3644
3645 3645 #header ul#logged-user,#content div.box div.title ul.links,
3646 3646 #content div.box div.message div.dismiss,
3647 3647 #content div.box div.traffic div.legend ul
3648 3648 {
3649 3649 float: right;
3650 3650 margin: 0;
3651 3651 padding: 0;
3652 3652 }
3653 3653
3654 3654 #header #header-inner #home,#header #header-inner #logo,
3655 3655 #content div.box ul.left,#content div.box ol.left,
3656 3656 #content div.box div.pagination-left,div#commit_history,
3657 3657 div#legend_data,div#legend_container,div#legend_choices
3658 3658 {
3659 3659 float: left;
3660 3660 }
3661 3661
3662 3662 #header #header-inner #quick li:hover ul ul,
3663 3663 #header #header-inner #quick li:hover ul ul ul,
3664 3664 #header #header-inner #quick li:hover ul ul ul ul,
3665 3665 #content #left #menu ul.closed,#content #left #menu li ul.collapsed,.yui-tt-shadow
3666 3666 {
3667 3667 display: none;
3668 3668 }
3669 3669
3670 3670 #header #header-inner #quick li:hover ul,#header #header-inner #quick li li:hover ul,#header #header-inner #quick li li li:hover ul,#header #header-inner #quick li li li li:hover ul,#content #left #menu ul.opened,#content #left #menu li ul.expanded
3671 3671 {
3672 3672 display: block;
3673 3673 }
3674 3674
3675 3675 #content div.graph {
3676 3676 padding: 0 10px 10px;
3677 3677 }
3678 3678
3679 3679 #content div.box div.title ul.links li a:hover,#content div.box div.title ul.links li.ui-tabs-selected a
3680 3680 {
3681 3681 color: #bfe3ff;
3682 3682 }
3683 3683
3684 3684 #content div.box ol.lower-roman,#content div.box ol.upper-roman,#content div.box ol.lower-alpha,#content div.box ol.upper-alpha,#content div.box ol.decimal
3685 3685 {
3686 3686 margin: 10px 24px 10px 44px;
3687 3687 }
3688 3688
3689 3689 #content div.box div.form,#content div.box div.table,#content div.box div.traffic
3690 3690 {
3691 3691 clear: both;
3692 3692 overflow: hidden;
3693 3693 margin: 0;
3694 3694 padding: 0 20px 10px;
3695 3695 }
3696 3696
3697 3697 #content div.box div.form div.fields,#login div.form,#login div.form div.fields,#register div.form,#register div.form div.fields
3698 3698 {
3699 3699 clear: both;
3700 3700 overflow: hidden;
3701 3701 margin: 0;
3702 3702 padding: 0;
3703 3703 }
3704 3704
3705 3705 #content div.box div.form div.fields div.field div.label span,#login div.form div.fields div.field div.label span,#register div.form div.fields div.field div.label span
3706 3706 {
3707 3707 height: 1%;
3708 3708 display: block;
3709 3709 color: #363636;
3710 3710 margin: 0;
3711 3711 padding: 2px 0 0;
3712 3712 }
3713 3713
3714 3714 #content div.box div.form div.fields div.field div.input input.error,#login div.form div.fields div.field div.input input.error,#register div.form div.fields div.field div.input input.error
3715 3715 {
3716 3716 background: #FBE3E4;
3717 3717 border-top: 1px solid #e1b2b3;
3718 3718 border-left: 1px solid #e1b2b3;
3719 3719 border-right: 1px solid #FBC2C4;
3720 3720 border-bottom: 1px solid #FBC2C4;
3721 3721 }
3722 3722
3723 3723 #content div.box div.form div.fields div.field div.input input.success,#login div.form div.fields div.field div.input input.success,#register div.form div.fields div.field div.input input.success
3724 3724 {
3725 3725 background: #E6EFC2;
3726 3726 border-top: 1px solid #cebb98;
3727 3727 border-left: 1px solid #cebb98;
3728 3728 border-right: 1px solid #c6d880;
3729 3729 border-bottom: 1px solid #c6d880;
3730 3730 }
3731 3731
3732 3732 #content div.box-left div.form div.fields div.field div.textarea,#content div.box-right div.form div.fields div.field div.textarea,#content div.box div.form div.fields div.field div.select select,#content div.box table th.selected input,#content div.box table td.selected input
3733 3733 {
3734 3734 margin: 0;
3735 3735 }
3736 3736
3737 3737 #content div.box-left div.form div.fields div.field div.select,#content div.box-left div.form div.fields div.field div.checkboxes,#content div.box-left div.form div.fields div.field div.radios,#content div.box-right div.form div.fields div.field div.select,#content div.box-right div.form div.fields div.field div.checkboxes,#content div.box-right div.form div.fields div.field div.radios
3738 3738 {
3739 3739 margin: 0 0 0 0px !important;
3740 3740 padding: 0;
3741 3741 }
3742 3742
3743 3743 #content div.box div.form div.fields div.field div.select,#content div.box div.form div.fields div.field div.checkboxes,#content div.box div.form div.fields div.field div.radios
3744 3744 {
3745 3745 margin: 0 0 0 200px;
3746 3746 padding: 0;
3747 3747 }
3748 3748
3749 3749 #content div.box div.form div.fields div.field div.select a:hover,#content div.box div.form div.fields div.field div.select a.ui-selectmenu:hover,#content div.box div.action a:hover
3750 3750 {
3751 3751 color: #000;
3752 3752 text-decoration: none;
3753 3753 }
3754 3754
3755 3755 #content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus,#content div.box div.action a.ui-selectmenu-focus
3756 3756 {
3757 3757 border: 1px solid #666;
3758 3758 }
3759 3759
3760 3760 #content div.box div.form div.fields div.field div.checkboxes div.checkbox,#content div.box div.form div.fields div.field div.radios div.radio
3761 3761 {
3762 3762 clear: both;
3763 3763 overflow: hidden;
3764 3764 margin: 0;
3765 3765 padding: 8px 0 2px;
3766 3766 }
3767 3767
3768 3768 #content div.box div.form div.fields div.field div.checkboxes div.checkbox input,#content div.box div.form div.fields div.field div.radios div.radio input
3769 3769 {
3770 3770 float: left;
3771 3771 margin: 0;
3772 3772 }
3773 3773
3774 3774 #content div.box div.form div.fields div.field div.checkboxes div.checkbox label,#content div.box div.form div.fields div.field div.radios div.radio label
3775 3775 {
3776 3776 height: 1%;
3777 3777 display: block;
3778 3778 float: left;
3779 3779 margin: 2px 0 0 4px;
3780 3780 }
3781 3781
3782 3782 div.form div.fields div.field div.button input,
3783 3783 #content div.box div.form div.fields div.buttons input
3784 3784 div.form div.fields div.buttons input,
3785 3785 #content div.box div.action div.button input {
3786 3786 /*color: #000;*/
3787 3787 font-size: 11px;
3788 3788 font-weight: 700;
3789 3789 margin: 0;
3790 3790 }
3791 3791
3792 3792 input.ui-button {
3793 3793 background: #e5e3e3 url("../images/button.png") repeat-x;
3794 3794 border-top: 1px solid #DDD;
3795 3795 border-left: 1px solid #c6c6c6;
3796 3796 border-right: 1px solid #DDD;
3797 3797 border-bottom: 1px solid #c6c6c6;
3798 3798 color: #515151 !important;
3799 3799 outline: none;
3800 3800 margin: 0;
3801 3801 padding: 6px 12px;
3802 3802 -webkit-border-radius: 4px 4px 4px 4px;
3803 3803 -khtml-border-radius: 4px 4px 4px 4px;
3804 3804 -moz-border-radius: 4px 4px 4px 4px;
3805 3805 border-radius: 4px 4px 4px 4px;
3806 3806 box-shadow: 0 1px 0 #ececec;
3807 3807 cursor: pointer;
3808 3808 }
3809 3809
3810 3810 input.ui-button:hover {
3811 3811 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
3812 3812 border-top: 1px solid #ccc;
3813 3813 border-left: 1px solid #bebebe;
3814 3814 border-right: 1px solid #b1b1b1;
3815 3815 border-bottom: 1px solid #afafaf;
3816 3816 }
3817 3817
3818 3818 div.form div.fields div.field div.highlight,#content div.box div.form div.fields div.buttons div.highlight
3819 3819 {
3820 3820 display: inline;
3821 3821 }
3822 3822
3823 3823 #content div.box div.form div.fields div.buttons,div.form div.fields div.buttons
3824 3824 {
3825 3825 margin: 10px 0 0 200px;
3826 3826 padding: 0;
3827 3827 }
3828 3828
3829 3829 #content div.box-left div.form div.fields div.buttons,#content div.box-right div.form div.fields div.buttons,div.box-left div.form div.fields div.buttons,div.box-right div.form div.fields div.buttons
3830 3830 {
3831 3831 margin: 10px 0 0;
3832 3832 }
3833 3833
3834 3834 #content div.box table td.user,#content div.box table td.address {
3835 3835 width: 10%;
3836 3836 text-align: center;
3837 3837 }
3838 3838
3839 3839 #content div.box div.action div.button,#login div.form div.fields div.field div.input div.link,#register div.form div.fields div.field div.input div.link
3840 3840 {
3841 3841 text-align: right;
3842 3842 margin: 6px 0 0;
3843 3843 padding: 0;
3844 3844 }
3845 3845
3846 3846 #content div.box div.action div.button input.ui-state-hover,#login div.form div.fields div.buttons input.ui-state-hover,#register div.form div.fields div.buttons input.ui-state-hover
3847 3847 {
3848 3848 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
3849 3849 border-top: 1px solid #ccc;
3850 3850 border-left: 1px solid #bebebe;
3851 3851 border-right: 1px solid #b1b1b1;
3852 3852 border-bottom: 1px solid #afafaf;
3853 3853 color: #515151;
3854 3854 margin: 0;
3855 3855 padding: 6px 12px;
3856 3856 }
3857 3857
3858 3858 #content div.box div.pagination div.results,#content div.box div.pagination-wh div.results
3859 3859 {
3860 3860 text-align: left;
3861 3861 float: left;
3862 3862 margin: 0;
3863 3863 padding: 0;
3864 3864 }
3865 3865
3866 3866 #content div.box div.pagination div.results span,#content div.box div.pagination-wh div.results span
3867 3867 {
3868 3868 height: 1%;
3869 3869 display: block;
3870 3870 float: left;
3871 3871 background: #ebebeb url("../images/pager.png") repeat-x;
3872 3872 border-top: 1px solid #dedede;
3873 3873 border-left: 1px solid #cfcfcf;
3874 3874 border-right: 1px solid #c4c4c4;
3875 3875 border-bottom: 1px solid #c4c4c4;
3876 3876 color: #4A4A4A;
3877 3877 font-weight: 700;
3878 3878 margin: 0;
3879 3879 padding: 6px 8px;
3880 3880 }
3881 3881
3882 3882 #content div.box div.pagination ul.pager li.disabled,#content div.box div.pagination-wh a.disabled
3883 3883 {
3884 3884 color: #B4B4B4;
3885 3885 padding: 6px;
3886 3886 }
3887 3887
3888 3888 #login,#register {
3889 3889 width: 520px;
3890 3890 margin: 10% auto 0;
3891 3891 padding: 0;
3892 3892 }
3893 3893
3894 3894 #login div.color,#register div.color {
3895 3895 clear: both;
3896 3896 overflow: hidden;
3897 3897 background: #FFF;
3898 3898 margin: 10px auto 0;
3899 3899 padding: 3px 3px 3px 0;
3900 3900 }
3901 3901
3902 3902 #login div.color a,#register div.color a {
3903 3903 width: 20px;
3904 3904 height: 20px;
3905 3905 display: block;
3906 3906 float: left;
3907 3907 margin: 0 0 0 3px;
3908 3908 padding: 0;
3909 3909 }
3910 3910
3911 3911 #login div.title h5,#register div.title h5 {
3912 3912 color: #fff;
3913 3913 margin: 10px;
3914 3914 padding: 0;
3915 3915 }
3916 3916
3917 3917 #login div.form div.fields div.field,#register div.form div.fields div.field
3918 3918 {
3919 3919 clear: both;
3920 3920 overflow: hidden;
3921 3921 margin: 0;
3922 3922 padding: 0 0 10px;
3923 3923 }
3924 3924
3925 3925 #login div.form div.fields div.field span.error-message,#register div.form div.fields div.field span.error-message
3926 3926 {
3927 3927 height: 1%;
3928 3928 display: block;
3929 3929 color: red;
3930 3930 margin: 8px 0 0;
3931 3931 padding: 0;
3932 3932 max-width: 320px;
3933 3933 }
3934 3934
3935 3935 #login div.form div.fields div.field div.label label,#register div.form div.fields div.field div.label label
3936 3936 {
3937 3937 color: #000;
3938 3938 font-weight: 700;
3939 3939 }
3940 3940
3941 3941 #login div.form div.fields div.field div.input,#register div.form div.fields div.field div.input
3942 3942 {
3943 3943 float: left;
3944 3944 margin: 0;
3945 3945 padding: 0;
3946 3946 }
3947 3947
3948 3948 #login div.form div.fields div.field div.checkbox,#register div.form div.fields div.field div.checkbox
3949 3949 {
3950 3950 margin: 0 0 0 184px;
3951 3951 padding: 0;
3952 3952 }
3953 3953
3954 3954 #login div.form div.fields div.field div.checkbox label,#register div.form div.fields div.field div.checkbox label
3955 3955 {
3956 3956 color: #565656;
3957 3957 font-weight: 700;
3958 3958 }
3959 3959
3960 3960 #login div.form div.fields div.buttons input,#register div.form div.fields div.buttons input
3961 3961 {
3962 3962 color: #000;
3963 3963 font-size: 1em;
3964 3964 font-weight: 700;
3965 3965 margin: 0;
3966 3966 }
3967 3967
3968 3968 #changeset_content .container .wrapper,#graph_content .container .wrapper
3969 3969 {
3970 3970 width: 600px;
3971 3971 }
3972 3972
3973 3973 #changeset_content .container .left {
3974 3974 float: left;
3975 3975 width: 75%;
3976 3976 padding-left: 5px;
3977 3977 }
3978 3978
3979 3979 #changeset_content .container .left .date,.ac .match {
3980 3980 font-weight: 700;
3981 3981 padding-top: 5px;
3982 3982 padding-bottom: 5px;
3983 3983 }
3984 3984
3985 3985 div#legend_container table td,div#legend_choices table td {
3986 3986 border: none !important;
3987 3987 height: 20px !important;
3988 3988 padding: 0 !important;
3989 3989 }
3990 3990
3991 3991 .q_filter_box {
3992 3992 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
3993 3993 -webkit-border-radius: 4px;
3994 3994 -moz-border-radius: 4px;
3995 3995 border-radius: 4px;
3996 3996 border: 0 none;
3997 3997 color: #AAAAAA;
3998 3998 margin-bottom: -4px;
3999 3999 margin-top: -4px;
4000 4000 padding-left: 3px;
4001 4001 }
4002 4002
4003 4003 #node_filter {
4004 4004 border: 0px solid #545454;
4005 4005 color: #AAAAAA;
4006 4006 padding-left: 3px;
4007 4007 }
4008 4008
4009 4009
4010 4010 .group_members_wrap{
4011 4011 min-height: 85px;
4012 4012 padding-left: 20px;
4013 4013 }
4014 4014
4015 4015 .group_members .group_member{
4016 4016 height: 30px;
4017 4017 padding:0px 0px 0px 0px;
4018 4018 }
4019 4019
4020 4020 .reviewers_member{
4021 4021 height: 15px;
4022 4022 padding:0px 0px 0px 10px;
4023 4023 }
4024 4024
4025 4025 .emails_wrap{
4026 4026 padding: 0px 20px;
4027 4027 }
4028 4028
4029 4029 .emails_wrap .email_entry{
4030 4030 height: 30px;
4031 4031 padding:0px 0px 0px 10px;
4032 4032 }
4033 4033 .emails_wrap .email_entry .email{
4034 4034 float: left
4035 4035 }
4036 4036 .emails_wrap .email_entry .email_action{
4037 4037 float: left
4038 4038 }
4039 4039
4040 4040 .ips_wrap{
4041 4041 padding: 0px 20px;
4042 4042 }
4043 4043
4044 4044 .ips_wrap .ip_entry{
4045 4045 height: 30px;
4046 4046 padding:0px 0px 0px 10px;
4047 4047 }
4048 4048 .ips_wrap .ip_entry .ip{
4049 4049 float: left
4050 4050 }
4051 4051 .ips_wrap .ip_entry .ip_action{
4052 4052 float: left
4053 4053 }
4054 4054
4055 4055
4056 4056 /*README STYLE*/
4057 4057
4058 4058 div.readme {
4059 4059 padding:0px;
4060 4060 }
4061 4061
4062 4062 div.readme h2 {
4063 4063 font-weight: normal;
4064 4064 }
4065 4065
4066 4066 div.readme .readme_box {
4067 4067 background-color: #fafafa;
4068 4068 }
4069 4069
4070 4070 div.readme .readme_box {
4071 4071 clear:both;
4072 4072 overflow:hidden;
4073 4073 margin:0;
4074 4074 padding:0 20px 10px;
4075 4075 }
4076 4076
4077 4077 div.readme .readme_box h1, div.readme .readme_box h2, div.readme .readme_box h3, div.readme .readme_box h4, div.readme .readme_box h5, div.readme .readme_box h6 {
4078 4078 border-bottom: 0 !important;
4079 4079 margin: 0 !important;
4080 4080 padding: 0 !important;
4081 4081 line-height: 1.5em !important;
4082 4082 }
4083 4083
4084 4084
4085 4085 div.readme .readme_box h1:first-child {
4086 4086 padding-top: .25em !important;
4087 4087 }
4088 4088
4089 4089 div.readme .readme_box h2, div.readme .readme_box h3 {
4090 4090 margin: 1em 0 !important;
4091 4091 }
4092 4092
4093 4093 div.readme .readme_box h2 {
4094 4094 margin-top: 1.5em !important;
4095 4095 border-top: 4px solid #e0e0e0 !important;
4096 4096 padding-top: .5em !important;
4097 4097 }
4098 4098
4099 4099 div.readme .readme_box p {
4100 4100 color: black !important;
4101 4101 margin: 1em 0 !important;
4102 4102 line-height: 1.5em !important;
4103 4103 }
4104 4104
4105 4105 div.readme .readme_box ul {
4106 4106 list-style: disc !important;
4107 4107 margin: 1em 0 1em 2em !important;
4108 4108 }
4109 4109
4110 4110 div.readme .readme_box ol {
4111 4111 list-style: decimal;
4112 4112 margin: 1em 0 1em 2em !important;
4113 4113 }
4114 4114
4115 4115 div.readme .readme_box pre, code {
4116 4116 font: 12px "Bitstream Vera Sans Mono","Courier",monospace;
4117 4117 }
4118 4118
4119 4119 div.readme .readme_box code {
4120 4120 font-size: 12px !important;
4121 4121 background-color: ghostWhite !important;
4122 4122 color: #444 !important;
4123 4123 padding: 0 .2em !important;
4124 4124 border: 1px solid #dedede !important;
4125 4125 }
4126 4126
4127 4127 div.readme .readme_box pre code {
4128 4128 padding: 0 !important;
4129 4129 font-size: 12px !important;
4130 4130 background-color: #eee !important;
4131 4131 border: none !important;
4132 4132 }
4133 4133
4134 4134 div.readme .readme_box pre {
4135 4135 margin: 1em 0;
4136 4136 font-size: 12px;
4137 4137 background-color: #eee;
4138 4138 border: 1px solid #ddd;
4139 4139 padding: 5px;
4140 4140 color: #444;
4141 4141 overflow: auto;
4142 4142 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4143 4143 -webkit-border-radius: 3px;
4144 4144 -moz-border-radius: 3px;
4145 4145 border-radius: 3px;
4146 4146 }
4147 4147
4148 4148 div.readme .readme_box table {
4149 4149 display: table;
4150 4150 border-collapse: separate;
4151 4151 border-spacing: 2px;
4152 4152 border-color: gray;
4153 4153 width: auto !important;
4154 4154 }
4155 4155
4156 4156
4157 4157 /** RST STYLE **/
4158 4158
4159 4159
4160 4160 div.rst-block {
4161 4161 padding:0px;
4162 4162 }
4163 4163
4164 4164 div.rst-block h2 {
4165 4165 font-weight: normal;
4166 4166 }
4167 4167
4168 4168 div.rst-block {
4169 4169 background-color: #fafafa;
4170 4170 }
4171 4171
4172 4172 div.rst-block {
4173 4173 clear:both;
4174 4174 overflow:hidden;
4175 4175 margin:0;
4176 4176 padding:0 20px 10px;
4177 4177 }
4178 4178
4179 4179 div.rst-block h1, div.rst-block h2, div.rst-block h3, div.rst-block h4, div.rst-block h5, div.rst-block h6 {
4180 4180 border-bottom: 0 !important;
4181 4181 margin: 0 !important;
4182 4182 padding: 0 !important;
4183 4183 line-height: 1.5em !important;
4184 4184 }
4185 4185
4186 4186
4187 4187 div.rst-block h1:first-child {
4188 4188 padding-top: .25em !important;
4189 4189 }
4190 4190
4191 4191 div.rst-block h2, div.rst-block h3 {
4192 4192 margin: 1em 0 !important;
4193 4193 }
4194 4194
4195 4195 div.rst-block h2 {
4196 4196 margin-top: 1.5em !important;
4197 4197 border-top: 4px solid #e0e0e0 !important;
4198 4198 padding-top: .5em !important;
4199 4199 }
4200 4200
4201 4201 div.rst-block p {
4202 4202 color: black !important;
4203 4203 margin: 1em 0 !important;
4204 4204 line-height: 1.5em !important;
4205 4205 }
4206 4206
4207 4207 div.rst-block ul {
4208 4208 list-style: disc !important;
4209 4209 margin: 1em 0 1em 2em !important;
4210 4210 }
4211 4211
4212 4212 div.rst-block ol {
4213 4213 list-style: decimal;
4214 4214 margin: 1em 0 1em 2em !important;
4215 4215 }
4216 4216
4217 4217 div.rst-block pre, code {
4218 4218 font: 12px "Bitstream Vera Sans Mono","Courier",monospace;
4219 4219 }
4220 4220
4221 4221 div.rst-block code {
4222 4222 font-size: 12px !important;
4223 4223 background-color: ghostWhite !important;
4224 4224 color: #444 !important;
4225 4225 padding: 0 .2em !important;
4226 4226 border: 1px solid #dedede !important;
4227 4227 }
4228 4228
4229 4229 div.rst-block pre code {
4230 4230 padding: 0 !important;
4231 4231 font-size: 12px !important;
4232 4232 background-color: #eee !important;
4233 4233 border: none !important;
4234 4234 }
4235 4235
4236 4236 div.rst-block pre {
4237 4237 margin: 1em 0;
4238 4238 font-size: 12px;
4239 4239 background-color: #eee;
4240 4240 border: 1px solid #ddd;
4241 4241 padding: 5px;
4242 4242 color: #444;
4243 4243 overflow: auto;
4244 4244 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4245 4245 -webkit-border-radius: 3px;
4246 4246 -moz-border-radius: 3px;
4247 4247 border-radius: 3px;
4248 4248 }
4249 4249
4250 4250
4251 4251 /** comment main **/
4252 4252 .comments {
4253 4253 padding:10px 20px;
4254 4254 }
4255 4255
4256 4256 .comments .comment {
4257 4257 border: 1px solid #ddd;
4258 4258 margin-top: 10px;
4259 4259 -webkit-border-radius: 4px;
4260 4260 -moz-border-radius: 4px;
4261 4261 border-radius: 4px;
4262 4262 }
4263 4263
4264 4264 .comments .comment .meta {
4265 4265 background: #f8f8f8;
4266 4266 padding: 4px;
4267 4267 border-bottom: 1px solid #ddd;
4268 4268 height: 18px;
4269 4269 }
4270 4270
4271 4271 .comments .comment .meta img {
4272 4272 vertical-align: middle;
4273 4273 }
4274 4274
4275 4275 .comments .comment .meta .user {
4276 4276 font-weight: bold;
4277 4277 float: left;
4278 4278 padding: 4px 2px 2px 2px;
4279 4279 }
4280 4280
4281 4281 .comments .comment .meta .date {
4282 4282 float: left;
4283 4283 padding:4px 4px 0px 4px;
4284 4284 }
4285 4285
4286 4286 .comments .comment .text {
4287 4287 background-color: #FAFAFA;
4288 4288 }
4289 4289 .comment .text div.rst-block p {
4290 4290 margin: 0.5em 0px !important;
4291 4291 }
4292 4292
4293 4293 .comments .comments-number{
4294 4294 padding:0px 0px 10px 0px;
4295 4295 font-weight: bold;
4296 4296 color: #666;
4297 4297 font-size: 16px;
4298 4298 }
4299 4299
4300 4300 /** comment form **/
4301 4301
4302 4302 .status-block{
4303 4303 height:80px;
4304 4304 clear:both
4305 4305 }
4306 4306
4307 4307 .comment-form .clearfix{
4308 4308 background: #EEE;
4309 4309 -webkit-border-radius: 4px;
4310 4310 -moz-border-radius: 4px;
4311 4311 border-radius: 4px;
4312 4312 padding: 10px;
4313 4313 }
4314 4314
4315 4315 div.comment-form {
4316 4316 margin-top: 20px;
4317 4317 }
4318 4318
4319 4319 .comment-form strong {
4320 4320 display: block;
4321 4321 margin-bottom: 15px;
4322 4322 }
4323 4323
4324 4324 .comment-form textarea {
4325 4325 width: 100%;
4326 4326 height: 100px;
4327 4327 font-family: 'Monaco', 'Courier', 'Courier New', monospace;
4328 4328 }
4329 4329
4330 4330 form.comment-form {
4331 4331 margin-top: 10px;
4332 4332 margin-left: 10px;
4333 4333 }
4334 4334
4335 4335 .comment-form-submit {
4336 4336 margin-top: 5px;
4337 4337 margin-left: 525px;
4338 4338 }
4339 4339
4340 4340 .file-comments {
4341 4341 display: none;
4342 4342 }
4343 4343
4344 4344 .comment-form .comment {
4345 4345 margin-left: 10px;
4346 4346 }
4347 4347
4348 4348 .comment-form .comment-help{
4349 4349 padding: 0px 0px 5px 0px;
4350 4350 color: #666;
4351 4351 }
4352 4352
4353 4353 .comment-form .comment-button{
4354 4354 padding-top:5px;
4355 4355 }
4356 4356
4357 4357 .add-another-button {
4358 4358 margin-left: 10px;
4359 4359 margin-top: 10px;
4360 4360 margin-bottom: 10px;
4361 4361 }
4362 4362
4363 4363 .comment .buttons {
4364 4364 float: right;
4365 4365 padding:2px 2px 0px 0px;
4366 4366 }
4367 4367
4368 4368
4369 4369 .show-inline-comments{
4370 4370 position: relative;
4371 4371 top:1px
4372 4372 }
4373 4373
4374 4374 /** comment inline form **/
4375 4375 .comment-inline-form .overlay{
4376 4376 display: none;
4377 4377 }
4378 4378 .comment-inline-form .overlay.submitting{
4379 4379 display:block;
4380 4380 background: none repeat scroll 0 0 white;
4381 4381 font-size: 16px;
4382 4382 opacity: 0.5;
4383 4383 position: absolute;
4384 4384 text-align: center;
4385 4385 vertical-align: top;
4386 4386
4387 4387 }
4388 4388 .comment-inline-form .overlay.submitting .overlay-text{
4389 4389 width:100%;
4390 4390 margin-top:5%;
4391 4391 }
4392 4392
4393 4393 .comment-inline-form .clearfix{
4394 4394 background: #EEE;
4395 4395 -webkit-border-radius: 4px;
4396 4396 -moz-border-radius: 4px;
4397 4397 border-radius: 4px;
4398 4398 padding: 5px;
4399 4399 }
4400 4400
4401 4401 div.comment-inline-form {
4402 4402 padding:4px 0px 6px 0px;
4403 4403 }
4404 4404
4405 4405
4406 4406 tr.hl-comment{
4407 4407 /*
4408 4408 background-color: #FFFFCC !important;
4409 4409 */
4410 4410 }
4411 4411
4412 4412 /*
4413 4413 tr.hl-comment pre {
4414 4414 border-top: 2px solid #FFEE33;
4415 4415 border-left: 2px solid #FFEE33;
4416 4416 border-right: 2px solid #FFEE33;
4417 4417 }
4418 4418 */
4419 4419
4420 4420 .comment-inline-form strong {
4421 4421 display: block;
4422 4422 margin-bottom: 15px;
4423 4423 }
4424 4424
4425 4425 .comment-inline-form textarea {
4426 4426 width: 100%;
4427 4427 height: 100px;
4428 4428 font-family: 'Monaco', 'Courier', 'Courier New', monospace;
4429 4429 }
4430 4430
4431 4431 form.comment-inline-form {
4432 4432 margin-top: 10px;
4433 4433 margin-left: 10px;
4434 4434 }
4435 4435
4436 4436 .comment-inline-form-submit {
4437 4437 margin-top: 5px;
4438 4438 margin-left: 525px;
4439 4439 }
4440 4440
4441 4441 .file-comments {
4442 4442 display: none;
4443 4443 }
4444 4444
4445 4445 .comment-inline-form .comment {
4446 4446 margin-left: 10px;
4447 4447 }
4448 4448
4449 4449 .comment-inline-form .comment-help{
4450 4450 padding: 0px 0px 2px 0px;
4451 4451 color: #666666;
4452 4452 font-size: 10px;
4453 4453 }
4454 4454
4455 4455 .comment-inline-form .comment-button{
4456 4456 padding-top:5px;
4457 4457 }
4458 4458
4459 4459 /** comment inline **/
4460 4460 .inline-comments {
4461 4461 padding:10px 20px;
4462 4462 }
4463 4463
4464 4464 .inline-comments div.rst-block {
4465 4465 clear:both;
4466 4466 overflow:hidden;
4467 4467 margin:0;
4468 4468 padding:0 20px 0px;
4469 4469 }
4470 4470 .inline-comments .comment {
4471 4471 border: 1px solid #ddd;
4472 4472 -webkit-border-radius: 4px;
4473 4473 -moz-border-radius: 4px;
4474 4474 border-radius: 4px;
4475 4475 margin: 3px 3px 5px 5px;
4476 4476 background-color: #FAFAFA;
4477 4477 }
4478 4478 .inline-comments .add-comment {
4479 4479 padding: 2px 4px 8px 5px;
4480 4480 }
4481 4481
4482 4482 .inline-comments .comment-wrapp{
4483 4483 padding:1px;
4484 4484 }
4485 4485 .inline-comments .comment .meta {
4486 4486 background: #f8f8f8;
4487 4487 padding: 4px;
4488 4488 border-bottom: 1px solid #ddd;
4489 4489 height: 20px;
4490 4490 }
4491 4491
4492 4492 .inline-comments .comment .meta img {
4493 4493 vertical-align: middle;
4494 4494 }
4495 4495
4496 4496 .inline-comments .comment .meta .user {
4497 4497 font-weight: bold;
4498 4498 float:left;
4499 4499 padding: 3px;
4500 4500 }
4501 4501
4502 4502 .inline-comments .comment .meta .date {
4503 4503 float:left;
4504 4504 padding: 3px;
4505 4505 }
4506 4506
4507 4507 .inline-comments .comment .text {
4508 4508 background-color: #FAFAFA;
4509 4509 }
4510 4510
4511 4511 .inline-comments .comments-number{
4512 4512 padding:0px 0px 10px 0px;
4513 4513 font-weight: bold;
4514 4514 color: #666;
4515 4515 font-size: 16px;
4516 4516 }
4517 4517 .inline-comments-button .add-comment{
4518 4518 margin:2px 0px 8px 5px !important
4519 4519 }
4520 4520
4521 4521
4522 4522 .notification-paginator{
4523 4523 padding: 0px 0px 4px 16px;
4524 4524 float: left;
4525 4525 }
4526 4526
4527 4527 .notifications{
4528 4528 border-radius: 4px 4px 4px 4px;
4529 4529 -webkit-border-radius: 4px;
4530 4530 -moz-border-radius: 4px;
4531 4531 float: right;
4532 4532 margin: 20px 0px 0px 0px;
4533 4533 position: absolute;
4534 4534 text-align: center;
4535 4535 width: 26px;
4536 4536 z-index: 1000;
4537 4537 }
4538 4538 .notifications a{
4539 4539 color:#888 !important;
4540 4540 display: block;
4541 4541 font-size: 10px;
4542 4542 background-color: #DEDEDE !important;
4543 4543 border-radius: 2px !important;
4544 4544 -webkit-border-radius: 2px !important;
4545 4545 -moz-border-radius: 2px !important;
4546 4546 }
4547 4547 .notifications a:hover{
4548 4548 text-decoration: none !important;
4549 4549 background-color: #EEEFFF !important;
4550 4550 }
4551 4551 .notification-header{
4552 4552 padding-top:6px;
4553 4553 }
4554 4554 .notification-header .desc{
4555 4555 font-size: 16px;
4556 4556 height: 24px;
4557 4557 float: left
4558 4558 }
4559 4559 .notification-list .container.unread{
4560 4560 background: none repeat scroll 0 0 rgba(255, 255, 180, 0.6);
4561 4561 }
4562 4562 .notification-header .gravatar{
4563 4563 background: none repeat scroll 0 0 transparent;
4564 4564 padding: 0px 0px 0px 8px;
4565 4565 }
4566 4566 .notification-list .container .notification-header .desc{
4567 4567 font-weight: bold;
4568 4568 font-size: 17px;
4569 4569 }
4570 4570 .notification-table{
4571 4571 border: 1px solid #ccc;
4572 4572 -webkit-border-radius: 6px 6px 6px 6px;
4573 4573 -moz-border-radius: 6px 6px 6px 6px;
4574 4574 border-radius: 6px 6px 6px 6px;
4575 4575 clear: both;
4576 4576 margin: 0px 20px 0px 20px;
4577 4577 }
4578 4578 .notification-header .delete-notifications{
4579 4579 float: right;
4580 4580 padding-top: 8px;
4581 4581 cursor: pointer;
4582 4582 }
4583 4583 .notification-header .read-notifications{
4584 4584 float: right;
4585 4585 padding-top: 8px;
4586 4586 cursor: pointer;
4587 4587 }
4588 4588 .notification-subject{
4589 4589 clear:both;
4590 4590 border-bottom: 1px solid #eee;
4591 4591 padding:5px 0px 5px 38px;
4592 4592 }
4593 4593
4594 4594 .notification-body{
4595 4595 clear:both;
4596 4596 margin: 34px 2px 2px 8px
4597 4597 }
4598 4598
4599 4599 /****
4600 4600 PULL REQUESTS
4601 4601 *****/
4602 4602 .pullrequests_section_head {
4603 4603 padding:10px 10px 10px 0px;
4604 4604 font-size:16px;
4605 4605 font-weight: bold;
4606 4606 }
4607 4607
4608 4608 /****
4609 4609 PERMS
4610 4610 *****/
4611 4611 #perms .perms_section_head {
4612 4612 padding:10px 10px 10px 0px;
4613 4613 font-size:16px;
4614 4614 font-weight: bold;
4615 4615 }
4616 4616
4617 4617 #perms .perm_tag{
4618 4618 padding: 1px 3px 1px 3px;
4619 4619 font-size: 10px;
4620 4620 font-weight: bold;
4621 4621 text-transform: uppercase;
4622 4622 white-space: nowrap;
4623 4623 -webkit-border-radius: 3px;
4624 4624 -moz-border-radius: 3px;
4625 4625 border-radius: 3px;
4626 4626 }
4627 4627
4628 4628 #perms .perm_tag.admin{
4629 4629 background-color: #B94A48;
4630 4630 color: #ffffff;
4631 4631 }
4632 4632
4633 4633 #perms .perm_tag.write{
4634 4634 background-color: #B94A48;
4635 4635 color: #ffffff;
4636 4636 }
4637 4637
4638 4638 #perms .perm_tag.read{
4639 4639 background-color: #468847;
4640 4640 color: #ffffff;
4641 4641 }
4642 4642
4643 4643 #perms .perm_tag.none{
4644 4644 background-color: #bfbfbf;
4645 4645 color: #ffffff;
4646 4646 }
4647 4647
4648 4648 .perm-gravatar{
4649 4649 vertical-align:middle;
4650 4650 padding:2px;
4651 4651 }
4652 4652 .perm-gravatar-ac{
4653 4653 vertical-align:middle;
4654 4654 padding:2px;
4655 4655 width: 14px;
4656 4656 height: 14px;
4657 4657 }
4658 4658
4659 4659 /*****************************************************************************
4660 4660 DIFFS CSS
4661 4661 ******************************************************************************/
4662 4662
4663 4663 div.diffblock {
4664 4664 overflow: auto;
4665 4665 padding: 0px;
4666 4666 border: 1px solid #ccc;
4667 4667 background: #f8f8f8;
4668 4668 font-size: 100%;
4669 4669 line-height: 100%;
4670 4670 /* new */
4671 4671 line-height: 125%;
4672 4672 -webkit-border-radius: 6px 6px 0px 0px;
4673 4673 -moz-border-radius: 6px 6px 0px 0px;
4674 4674 border-radius: 6px 6px 0px 0px;
4675 4675 }
4676 4676 div.diffblock.margined{
4677 4677 margin: 0px 20px 0px 20px;
4678 4678 }
4679 4679 div.diffblock .code-header{
4680 4680 border-bottom: 1px solid #CCCCCC;
4681 4681 background: #EEEEEE;
4682 4682 padding:10px 0 10px 0;
4683 4683 height: 14px;
4684 4684 }
4685 4685
4686 4686 div.diffblock .code-header.banner{
4687 4687 border-bottom: 1px solid #CCCCCC;
4688 4688 background: #EEEEEE;
4689 4689 height: 14px;
4690 4690 margin: 0px 95px 0px 95px;
4691 4691 padding: 3px 3px 11px 3px;
4692 4692 }
4693 4693
4694 4694 div.diffblock .code-header.cv{
4695 4695 height: 34px;
4696 4696 }
4697 4697 div.diffblock .code-header-title{
4698 4698 padding: 0px 0px 10px 5px !important;
4699 4699 margin: 0 !important;
4700 4700 }
4701 4701 div.diffblock .code-header .hash{
4702 4702 float: left;
4703 4703 padding: 2px 0 0 2px;
4704 4704 }
4705 4705 div.diffblock .code-header .date{
4706 4706 float:left;
4707 4707 text-transform: uppercase;
4708 4708 padding: 2px 0px 0px 2px;
4709 4709 }
4710 4710 div.diffblock .code-header div{
4711 4711 margin-left:4px;
4712 4712 font-weight: bold;
4713 4713 font-size: 14px;
4714 4714 }
4715 4715
4716 4716 div.diffblock .parents {
4717 4717 float: left;
4718 4718 height: 26px;
4719 4719 width:100px;
4720 4720 font-size: 10px;
4721 4721 font-weight: 400;
4722 4722 vertical-align: middle;
4723 4723 padding: 0px 2px 2px 2px;
4724 4724 background-color:#eeeeee;
4725 4725 border-bottom: 1px solid #CCCCCC;
4726 4726 }
4727 4727
4728 4728 div.diffblock .children {
4729 4729 float: right;
4730 4730 height: 26px;
4731 4731 width:100px;
4732 4732 font-size: 10px;
4733 4733 font-weight: 400;
4734 4734 vertical-align: middle;
4735 4735 text-align: right;
4736 4736 padding: 0px 2px 2px 2px;
4737 4737 background-color:#eeeeee;
4738 4738 border-bottom: 1px solid #CCCCCC;
4739 4739 }
4740 4740
4741 4741 div.diffblock .code-body{
4742 4742 background: #FFFFFF;
4743 4743 }
4744 4744 div.diffblock pre.raw{
4745 4745 background: #FFFFFF;
4746 4746 color:#000000;
4747 4747 }
4748 4748 table.code-difftable{
4749 4749 border-collapse: collapse;
4750 4750 width: 99%;
4751 4751 }
4752 4752 table.code-difftable td {
4753 4753 padding: 0 !important;
4754 4754 background: none !important;
4755 4755 border:0 !important;
4756 4756 vertical-align: none !important;
4757 4757 }
4758 4758 table.code-difftable .context{
4759 4759 background:none repeat scroll 0 0 #DDE7EF;
4760 4760 }
4761 4761 table.code-difftable .add{
4762 4762 background:none repeat scroll 0 0 #DDFFDD;
4763 4763 }
4764 4764 table.code-difftable .add ins{
4765 4765 background:none repeat scroll 0 0 #AAFFAA;
4766 4766 text-decoration:none;
4767 4767 }
4768 4768 table.code-difftable .del{
4769 4769 background:none repeat scroll 0 0 #FFDDDD;
4770 4770 }
4771 4771 table.code-difftable .del del{
4772 4772 background:none repeat scroll 0 0 #FFAAAA;
4773 4773 text-decoration:none;
4774 4774 }
4775 4775
4776 4776 /** LINE NUMBERS **/
4777 4777 table.code-difftable .lineno{
4778 4778
4779 4779 padding-left:2px;
4780 4780 padding-right:2px;
4781 4781 text-align:right;
4782 4782 width:32px;
4783 4783 -moz-user-select:none;
4784 4784 -webkit-user-select: none;
4785 4785 border-right: 1px solid #CCC !important;
4786 4786 border-left: 0px solid #CCC !important;
4787 4787 border-top: 0px solid #CCC !important;
4788 4788 border-bottom: none !important;
4789 4789 vertical-align: middle !important;
4790 4790
4791 4791 }
4792 4792 table.code-difftable .lineno.new {
4793 4793 }
4794 4794 table.code-difftable .lineno.old {
4795 4795 }
4796 4796 table.code-difftable .lineno a{
4797 4797 color:#747474 !important;
4798 4798 font:11px "Bitstream Vera Sans Mono",Monaco,"Courier New",Courier,monospace !important;
4799 4799 letter-spacing:-1px;
4800 4800 text-align:right;
4801 4801 padding-right: 2px;
4802 4802 cursor: pointer;
4803 4803 display: block;
4804 4804 width: 32px;
4805 4805 }
4806 4806
4807 4807 table.code-difftable .lineno-inline{
4808 4808 background:none repeat scroll 0 0 #FFF !important;
4809 4809 padding-left:2px;
4810 4810 padding-right:2px;
4811 4811 text-align:right;
4812 4812 width:30px;
4813 4813 -moz-user-select:none;
4814 4814 -webkit-user-select: none;
4815 4815 }
4816 4816
4817 4817 /** CODE **/
4818 4818 table.code-difftable .code {
4819 4819 display: block;
4820 4820 width: 100%;
4821 4821 }
4822 4822 table.code-difftable .code td{
4823 4823 margin:0;
4824 4824 padding:0;
4825 4825 }
4826 4826 table.code-difftable .code pre{
4827 4827 margin:0;
4828 4828 padding:0;
4829 4829 height: 17px;
4830 4830 line-height: 17px;
4831 4831 }
4832 4832
4833 4833
4834 4834 .diffblock.margined.comm .line .code:hover{
4835 4835 background-color:#FFFFCC !important;
4836 4836 cursor: pointer !important;
4837 4837 background-image:url("../images/icons/comment_add.png") !important;
4838 4838 background-repeat:no-repeat !important;
4839 4839 background-position: right !important;
4840 4840 background-position: 0% 50% !important;
4841 4841 }
4842 4842 .diffblock.margined.comm .line .code.no-comment:hover{
4843 4843 background-image: none !important;
4844 4844 cursor: auto !important;
4845 4845 background-color: inherit !important;
4846 4846
4847 4847 }
@@ -1,135 +1,142 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('Repositories administration')} - ${c.rhodecode_name}
6 6 </%def>
7 7
8 8 <%def name="breadcrumbs_links()">
9 9 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/> ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; <span id="repo_count">0</span> ${_('repositories')}
10 10 </%def>
11 11 <%def name="page_nav()">
12 12 ${self.menu('admin')}
13 13 </%def>
14 14 <%def name="main()">
15 15 <div class="box">
16 16
17 17 <div class="title">
18 18 ${self.breadcrumbs()}
19 19 <ul class="links">
20 20 <li>
21 21 <span>${h.link_to(_(u'ADD REPOSITORY'),h.url('new_repo'))}</span>
22 22 </li>
23 23 </ul>
24 24 </div>
25 25 <div class="table yui-skin-sam" id="repos_list_wrap"></div>
26 26 <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
27 27
28 28
29 29 </div>
30 30 <script>
31 31 var url = "${h.url('formatted_users', format='json')}";
32 32 var data = ${c.data|n};
33 33 var myDataSource = new YAHOO.util.DataSource(data);
34 34 myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
35 35
36 36 myDataSource.responseSchema = {
37 37 resultsList: "records",
38 38 fields: [
39 39 {key:"menu"},
40 40 {key:"raw_name"},
41 41 {key:"name"},
42 42 {key:"desc"},
43 {key:"last_changeset"},
43 44 {key:"owner"},
44 45 {key:"action"},
45 46 ]
46 47 };
47 48 myDataSource.doBeforeCallback = function(req,raw,res,cb) {
48 49 // This is the filter function
49 50 var data = res.results || [],
50 51 filtered = [],
51 52 i,l;
52 53
53 54 if (req) {
54 55 req = req.toLowerCase();
55 56 for (i = 0; i<data.length; i++) {
56 57 var pos = data[i].raw_name.toLowerCase().indexOf(req)
57 58 if (pos != -1) {
58 59 filtered.push(data[i]);
59 60 }
60 61 }
61 62 res.results = filtered;
62 63 }
63 64 YUD.get('repo_count').innerHTML = res.results.length;
64 65 return res;
65 66 }
66 67
67 68 // main table sorting
68 69 var myColumnDefs = [
69 70 {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
70 71 {key:"name",label:"${_('Name')}",sortable:true,
71 72 sortOptions: { sortFunction: nameSort }},
72 73 {key:"desc",label:"${_('Description')}",sortable:true},
74 {key:"last_changeset",label:"${_('Tip')}",sortable:true,
75 sortOptions: { sortFunction: revisionSort }},
73 76 {key:"owner",label:"${_('Owner')}",sortable:true},
74 77 {key:"action",label:"${_('Action')}",sortable:false},
75 78 ];
76 79
77 80 var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{
78 81 sortedBy:{key:"name",dir:"asc"},
79 82 paginator: new YAHOO.widget.Paginator({
80 rowsPerPage: 15,
83 rowsPerPage: 25,
81 84 alwaysVisible: false,
82 85 template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}",
83 86 pageLinks: 5,
84 87 containerClass: 'pagination-wh',
85 88 currentPageClass: 'pager_curpage',
86 89 pageLinkClass: 'pager_link',
87 90 nextPageLinkLabel: '&gt;',
88 91 previousPageLinkLabel: '&lt;',
89 92 firstPageLinkLabel: '&lt;&lt;',
90 93 lastPageLinkLabel: '&gt;&gt;',
91 94 containers:['user-paginator']
92 95 }),
93 96
94 97 MSG_SORTASC:"${_('Click to sort ascending')}",
95 98 MSG_SORTDESC:"${_('Click to sort descending')}",
96 99 MSG_EMPTY:"${_('No records found.')}",
97 100 MSG_ERROR:"${_('Data error.')}",
98 101 MSG_LOADING:"${_('Loading...')}",
99 102 }
100 103 );
101 104 myDataTable.subscribe('postRenderEvent',function(oArgs) {
102 105 tooltip_activate();
103 106 quick_repo_menu();
104 107 });
105 108
106 109 var filterTimeout = null;
107 110
108 111 updateFilter = function () {
109 112 // Reset timeout
110 113 filterTimeout = null;
111 114
112 115 // Reset sort
113 116 var state = myDataTable.getState();
114 117 state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC};
115 118
116 119 // Get filtered data
117 120 myDataSource.sendRequest(YUD.get('q_filter').value,{
118 121 success : myDataTable.onDataReturnInitializeTable,
119 122 failure : myDataTable.onDataReturnInitializeTable,
120 123 scope : myDataTable,
121 124 argument: state
122 125 });
123 126
124 127 };
125 128 YUE.on('q_filter','click',function(){
129 if(!YUD.hasClass('q_filter', 'loaded')){
126 130 YUD.get('q_filter').value = '';
131 //TODO: load here full list later to do search within groups
132 YUD.addClass('q_filter', 'loaded');
133 }
127 134 });
128 135
129 136 YUE.on('q_filter','keyup',function (e) {
130 137 clearTimeout(filterTimeout);
131 138 filterTimeout = setTimeout(updateFilter,600);
132 139 });
133 140 </script>
134 141
135 142 </%def>
@@ -1,248 +1,278 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('My account')} ${c.rhodecode_user.username} - ${c.rhodecode_name}
6 6 </%def>
7 7
8 8 <%def name="breadcrumbs_links()">
9 9 ${_('My Account')}
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
18 18 <div class="box box-left">
19 19 <!-- box / title -->
20 20 <div class="title">
21 21 ${self.breadcrumbs()}
22 22 </div>
23 23 <!-- end box / title -->
24 24 ${c.form|n}
25 25 </div>
26 26
27 27 <div class="box box-right">
28 28 <!-- box / title -->
29 29 <div class="title">
30 30 <h5>
31 31 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}" style="display: none"/>
32 32 </h5>
33 33 <ul class="links" style="color:#DADADA">
34 34 <li>
35 35 <span><a id="show_perms" class="link-white current" href="#perms">${_('My permissions')}</a> </span>
36 36 </li>
37 37 <li>
38 38 <span><a id="show_my" class="link-white" href="#my">${_('My repos')}</a> </span>
39 39 </li>
40 40 <li>
41 41 <span><a id="show_pullrequests" class="link-white" href="#pullrequests">${_('My pull requests')}</a> </span>
42 42 </li>
43 43 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
44 44 <li>
45 45 <span>${h.link_to(_('Add repo'),h.url('admin_settings_create_repository'))}</span>
46 46 </li>
47 47 %endif
48 48 </ul>
49 49 </div>
50 50 <!-- end box / title -->
51 <div id="perms" class="table">
51 <div id="perms_container" class="table">
52 52 %for section in sorted(c.rhodecode_user.permissions.keys()):
53 53 <div class="perms_section_head">${section.replace("_"," ").capitalize()}</div>
54 54
55 55 <div id='tbl_list_wrap_${section}' class="yui-skin-sam">
56 56 <table id="tbl_list_${section}">
57 57 <thead>
58 58 <tr>
59 59 <th class="left">${_('Name')}</th>
60 60 <th class="left">${_('Permission')}</th>
61 61 </thead>
62 62 <tbody>
63 63 %for k in c.rhodecode_user.permissions[section]:
64 64 <%
65 65 if section != 'global':
66 66 section_perm = c.rhodecode_user.permissions[section].get(k)
67 67 _perm = section_perm.split('.')[-1]
68 68 else:
69 69 _perm = section_perm = None
70 70 %>
71 71 %if _perm not in ['none']:
72 72 <tr>
73 73 <td>
74 74 %if section == 'repositories':
75 75 <a href="${h.url('summary_home',repo_name=k)}">${k}</a>
76 76 %elif section == 'repositories_groups':
77 77 <a href="${h.url('repos_group_home',group_name=k)}">${k}</a>
78 78 %else:
79 79 ${k}
80 80 %endif
81 81 </td>
82 82 <td>
83 83 %if section == 'global':
84 84 ${h.bool2icon(True)}
85 85 %else:
86 86 <span class="perm_tag ${_perm}">${section_perm}</span>
87 87 %endif
88 88 </td>
89 89 </tr>
90 90 %endif
91 91 %endfor
92 92 </tbody>
93 93 </table>
94 94 </div>
95 95 %endfor
96 96 </div>
97 <div id="my" class="table" style="display:none">
97 <div id="my_container" style="display:none">
98 <div class="table yui-skin-sam" id="repos_list_wrap"></div>
99 <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
98 100 </div>
99 <div id="pullrequests" class="table" style="display:none"></div>
101 <div id="pullrequests_container" class="table" style="display:none">
102 ## loaded via AJAX
103 ${_('Loading...')}
100 104 </div>
101
102
105 </div>
103 106
104 107 <script type="text/javascript">
105 var filter_activate = function(){
106 var nodes = YUQ('#my tr td a.repo_name');
107 var func = function(node){
108 return node.parentNode.parentNode.parentNode.parentNode;
109 }
110 q_filter('q_filter',YUQ('#my tr td a.repo_name'),func);
111 }
112 108
113 109 var show_perms = function(e){
114 110 YUD.addClass('show_perms', 'current');
115 111 YUD.removeClass('show_my','current');
116 112 YUD.removeClass('show_pullrequests','current');
117 113
118 YUD.setStyle('my','display','none');
119 YUD.setStyle('pullrequests','display','none');
120 YUD.setStyle('perms','display','');
114 YUD.setStyle('my_container','display','none');
115 YUD.setStyle('pullrequests_container','display','none');
116 YUD.setStyle('perms_container','display','');
121 117 YUD.setStyle('q_filter','display','none');
122 118 }
123 119 YUE.on('show_perms','click',function(e){
124 120 show_perms();
125 121 })
126 122
127 123 var show_my = function(e){
128 124 YUD.addClass('show_my', 'current');
129 125 YUD.removeClass('show_perms','current');
130 126 YUD.removeClass('show_pullrequests','current');
131 127
132 YUD.setStyle('perms','display','none');
133 YUD.setStyle('pullrequests','display','none');
134 YUD.setStyle('my','display','');
128 YUD.setStyle('perms_container','display','none');
129 YUD.setStyle('pullrequests_container','display','none');
130 YUD.setStyle('my_container','display','');
135 131 YUD.setStyle('q_filter','display','');
136
137
138 var url = "${h.url('journal_my_repos')}";
139 ypjax(url, 'my', function(){
140 table_sort();
141 filter_activate();
142 });
132 if(!YUD.hasClass('show_my', 'loaded')){
133 table_renderer(${c.data |n});
134 YUD.addClass('show_my', 'loaded');
135 }
143 136 }
144 137 YUE.on('show_my','click',function(e){
145 138 show_my(e);
146 139 })
147 140
148 141 var show_pullrequests = function(e){
149 142 YUD.addClass('show_pullrequests', 'current');
150 143 YUD.removeClass('show_my','current');
151 144 YUD.removeClass('show_perms','current');
152 145
153 YUD.setStyle('my','display','none');
154 YUD.setStyle('perms','display','none');
155 YUD.setStyle('pullrequests','display','');
146 YUD.setStyle('my_container','display','none');
147 YUD.setStyle('perms_container','display','none');
148 YUD.setStyle('pullrequests_container','display','');
156 149 YUD.setStyle('q_filter','display','none');
157 150
158 151 var url = "${h.url('admin_settings_my_pullrequests')}";
159 ypjax(url, 'pullrequests');
152 ypjax(url, 'pullrequests_container');
160 153 }
161 154 YUE.on('show_pullrequests','click',function(e){
162 155 show_pullrequests(e)
163 156 })
164 157
165 158 var tabs = {
166 159 'perms': show_perms,
167 160 'my': show_my,
168 161 'pullrequests': show_pullrequests
169 162 }
170 163 var url = location.href.split('#');
171 164 if (url[1]) {
172 165 //We have a hash
173 166 var tabHash = url[1];
174 167 var func = tabs[tabHash]
175 168 if (func){
176 169 func();
177 170 }
178 171 }
179 172
173 function table_renderer(data){
174 var myDataSource = new YAHOO.util.DataSource(data);
175 myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
176
177 myDataSource.responseSchema = {
178 resultsList: "records",
179 fields: [
180 {key:"menu"},
181 {key:"raw_name"},
182 {key:"name"},
183 {key:"last_changeset"},
184 {key:"action"},
185 ]
186 };
187 myDataSource.doBeforeCallback = function(req,raw,res,cb) {
188 // This is the filter function
189 var data = res.results || [],
190 filtered = [],
191 i,l;
192
193 if (req) {
194 req = req.toLowerCase();
195 for (i = 0; i<data.length; i++) {
196 var pos = data[i].raw_name.toLowerCase().indexOf(req)
197 if (pos != -1) {
198 filtered.push(data[i]);
199 }
200 }
201 res.results = filtered;
202 }
203 return res;
204 }
205
180 206 // main table sorting
181 207 var myColumnDefs = [
182 208 {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
183 209 {key:"name",label:"${_('Name')}",sortable:true,
184 210 sortOptions: { sortFunction: nameSort }},
185 {key:"tip",label:"${_('Tip')}",sortable:true,
211 {key:"last_changeset",label:"${_('Tip')}",sortable:true,
186 212 sortOptions: { sortFunction: revisionSort }},
187 {key:"action1",label:"",sortable:false},
188 {key:"action2",label:"",sortable:false},
213 {key:"action",label:"${_('Action')}",sortable:false},
189 214 ];
190 215
191 function table_sort(){
192 var myDataSource = new YAHOO.util.DataSource(YUD.get("repos_list"));
193 myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
194 myDataSource.responseSchema = {
195 fields: [
196 {key:"menu"},
197 {key:"name"},
198 {key:"tip"},
199 {key:"action1"},
200 {key:"action2"},
201 ]
202 };
203 var trans_defs = {
216 var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{
204 217 sortedBy:{key:"name",dir:"asc"},
218 paginator: new YAHOO.widget.Paginator({
219 rowsPerPage: 50,
220 alwaysVisible: false,
221 template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}",
222 pageLinks: 5,
223 containerClass: 'pagination-wh',
224 currentPageClass: 'pager_curpage',
225 pageLinkClass: 'pager_link',
226 nextPageLinkLabel: '&gt;',
227 previousPageLinkLabel: '&lt;',
228 firstPageLinkLabel: '&lt;&lt;',
229 lastPageLinkLabel: '&gt;&gt;',
230 containers:['user-paginator']
231 }),
232
205 233 MSG_SORTASC:"${_('Click to sort ascending')}",
206 234 MSG_SORTDESC:"${_('Click to sort descending')}",
207 235 MSG_EMPTY:"${_('No records found.')}",
208 236 MSG_ERROR:"${_('Data error.')}",
209 237 MSG_LOADING:"${_('Loading...')}",
210 238 }
211 var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,trans_defs);
239 );
212 240 myDataTable.subscribe('postRenderEvent',function(oArgs) {
213 241 tooltip_activate();
214 242 quick_repo_menu();
215 filter_activate();
216 243 });
217 244
218 var permsColumnDefs = [
219 {key:"name",label:"${_('Name')}",sortable:true, sortOptions: { sortFunction: permNameSort }},
220 {key:"perm",label:"${_('Permission')}",sortable:false,},
221 ];
245 var filterTimeout = null;
246
247 updateFilter = function() {
248 // Reset timeout
249 filterTimeout = null;
222 250
223 // perms repos table
224 var myDataSource2 = new YAHOO.util.DataSource(YUD.get("tbl_list_repositories"));
225 myDataSource2.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
226 myDataSource2.responseSchema = {
227 fields: [
228 {key:"name"},
229 {key:"perm"},
230 ]
251 // Reset sort
252 var state = myDataTable.getState();
253 state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC};
254
255 // Get filtered data
256 myDataSource.sendRequest(YUD.get('q_filter').value,{
257 success : myDataTable.onDataReturnInitializeTable,
258 failure : myDataTable.onDataReturnInitializeTable,
259 scope : myDataTable,
260 argument: state
261 });
262
231 263 };
232
233 new YAHOO.widget.DataTable("tbl_list_wrap_repositories", permsColumnDefs, myDataSource2, trans_defs);
264 YUE.on('q_filter','click',function(){
265 if(!YUD.hasClass('q_filter', 'loaded')){
266 YUD.get('q_filter').value = '';
267 //TODO: load here full list later to do search within groups
268 YUD.addClass('q_filter', 'loaded');
269 }
270 });
234 271
235 //perms groups table
236 var myDataSource3 = new YAHOO.util.DataSource(YUD.get("tbl_list_repositories_groups"));
237 myDataSource3.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
238 myDataSource3.responseSchema = {
239 fields: [
240 {key:"name"},
241 {key:"perm"},
242 ]
243 };
244
245 new YAHOO.widget.DataTable("tbl_list_wrap_repositories_groups", permsColumnDefs, myDataSource3, trans_defs);
272 YUE.on('q_filter','keyup',function (e) {
273 clearTimeout(filterTimeout);
274 filterTimeout = setTimeout(updateFilter,600);
275 });
246 276 }
247 277 </script>
248 278 </%def>
@@ -1,46 +1,1 b''
1 <div id='repos_list_wrap' class="yui-skin-sam">
2 <table id="repos_list">
3 <thead>
4 <tr>
5 <th></th>
6 <th class="left">${_('Name')}</th>
7 <th class="left">${_('Revision')}</th>
8 <th class="left">${_('Action')}</th>
9 <th class="left">${_('Action')}</th>
10 </thead>
11 <tbody>
12 <%namespace name="dt" file="/data_table/_dt_elements.html"/>
13 %if c.user_repos:
14 %for repo in c.user_repos:
15 <tr>
16 ##QUICK MENU
17 <td class="quick_repo_menu">
18 ${dt.quick_menu(repo['name'])}
19 </td>
20 ##REPO NAME AND ICONS
21 <td class="reponame">
22 ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],h.AttributeDict(repo['dbrepo_fork']))}
23 </td>
24 ##LAST REVISION
25 <td>
26 ${dt.revision(repo['name'],repo['rev'],repo['tip'],repo['author'],repo['last_msg'])}
27 </td>
28 <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>
30 ${h.form(url('repo_settings_delete', repo_name=repo['name']),method='delete')}
31 ${h.submit('remove_%s' % repo['name'],'',class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo['name']+"');")}
32 ${h.end_form()}
33 </td>
34 </tr>
35 %endfor
36 %else:
37 <div style="padding:5px 0px 10px 0px;">
38 ${_('No repositories yet')}
39 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
40 ${h.link_to(_('create one now'),h.url('admin_settings_create_repository'),class_="ui-btn")}
41 %endif
42 </div>
43 %endif
44 </tbody>
45 </table>
46 </div>
1
@@ -1,128 +1,144 b''
1 1 ## DATA TABLE RE USABLE ELEMENTS
2 2 ## usage:
3 3 ## <%namespace name="dt" file="/data_table/_dt_elements.html"/>
4 4
5 <%def name="repo_actions(repo_name)">
6 ${h.form(h.url('repo', repo_name=repo_name),method='delete')}
7 ${h.submit('remove_%s' % repo_name,_('delete'),class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo_name+"');")}
8 ${h.end_form()}
9 </%def>
10
11 5 <%def name="quick_menu(repo_name)">
12 6 <ul class="menu_items hidden">
13 7 <li style="border-top:1px solid #003367;margin-left:18px;padding-left:-99px"></li>
14 8 <li>
15 9 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=repo_name)}">
16 10 <span class="icon">
17 11 <img src="${h.url('/images/icons/clipboard_16.png')}" alt="${_('Summary')}" />
18 12 </span>
19 13 <span>${_('Summary')}</span>
20 14 </a>
21 15 </li>
22 16 <li>
23 17 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=repo_name)}">
24 18 <span class="icon">
25 19 <img src="${h.url('/images/icons/time.png')}" alt="${_('Changelog')}" />
26 20 </span>
27 21 <span>${_('Changelog')}</span>
28 22 </a>
29 23 </li>
30 24 <li>
31 25 <a title="${_('Files')}" href="${h.url('files_home',repo_name=repo_name)}">
32 26 <span class="icon">
33 27 <img src="${h.url('/images/icons/file.png')}" alt="${_('Files')}" />
34 28 </span>
35 29 <span>${_('Files')}</span>
36 30 </a>
37 31 </li>
38 32 <li>
39 33 <a title="${_('Fork')}" href="${h.url('repo_fork_home',repo_name=repo_name)}">
40 34 <span class="icon">
41 35 <img src="${h.url('/images/icons/arrow_divide.png')}" alt="${_('Fork')}" />
42 36 </span>
43 37 <span>${_('Fork')}</span>
44 38 </a>
45 39 </li>
46 40 </ul>
47 41 </%def>
48 42
49 43 <%def name="repo_name(name,rtype,private,fork_of,short_name=False, admin=False)">
50 44 <%
51 45 def get_name(name,short_name=short_name):
52 46 if short_name:
53 47 return name.split('/')[-1]
54 48 else:
55 49 return name
56 50 %>
57 51 <div style="white-space: nowrap">
58 52 ##TYPE OF REPO
59 53 %if h.is_hg(rtype):
60 54 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
61 55 %elif h.is_git(rtype):
62 56 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
63 57 %endif
64 58
65 59 ##PRIVATE/PUBLIC
66 60 %if private and c.visual.show_private_icon:
67 61 <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
68 62 %elif not private and c.visual.show_public_icon:
69 63 <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
70 64 %endif
71 65
72 66 ##NAME
73 67 %if admin:
74 68 ${h.link_to(get_name(name),h.url('edit_repo',repo_name=name),class_="repo_name")}
75 69 %else:
76 70 ${h.link_to(get_name(name),h.url('summary_home',repo_name=name),class_="repo_name")}
77 71 %endif
78 72 %if fork_of:
79 73 <a href="${h.url('summary_home',repo_name=fork_of.repo_name)}">
80 74 <img class="icon" alt="${_('fork')}" title="${_('Fork of')} ${fork_of.repo_name}" src="${h.url('/images/icons/arrow_divide.png')}"/></a>
81 75 %endif
82 76 </div>
83 77 </%def>
84 78
85 79 <%def name="last_change(last_change)">
86 80 <span class="tooltip" date="${last_change}" title="${h.tooltip(h.fmt_date(last_change))}">${h.age(last_change)}</span>
87 81 </%def>
88 82
89 83 <%def name="revision(name,rev,tip,author,last_msg)">
90 84 <div>
91 85 %if rev >= 0:
92 86 <pre><a title="${h.tooltip('%s:\n\n%s' % (author,last_msg))}" class="tooltip" href="${h.url('changeset_home',repo_name=name,revision=tip)}">${'r%s:%s' % (rev,h.short_id(tip))}</a></pre>
93 87 %else:
94 88 ${_('No changesets yet')}
95 89 %endif
96 90 </div>
97 91 </%def>
98 92
99 93 <%def name="rss(name)">
100 94 %if c.rhodecode_user.username != 'default':
101 95 <a title="${_('Subscribe to %s rss feed')% name}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=name,api_key=c.rhodecode_user.api_key)}"></a>
102 96 %else:
103 97 <a title="${_('Subscribe to %s rss feed')% name}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=name)}"></a>
104 98 %endif
105 99 </%def>
106 100
107 101 <%def name="atom(name)">
108 102 %if c.rhodecode_user.username != 'default':
109 103 <a title="${_('Subscribe to %s atom feed')% name}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=name,api_key=c.rhodecode_user.api_key)}"></a>
110 104 %else:
111 105 <a title="${_('Subscribe to %s atom feed')% name}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=name)}"></a>
112 106 %endif
113 107 </%def>
114 108
115 109 <%def name="user_gravatar(email, size=24)">
116 110 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(email, size)}"/> </div>
117 111 </%def>
118 112
113 <%def name="repo_actions(repo_name)">
114 <div>
115 <div style="float:left">
116 <a href="${h.url('repo_settings_home',repo_name=repo_name)}" title="${_('edit')}">
117 ${h.submit('edit_%s' % repo_name,_('edit'),class_="edit_icon action_button")}
118 </a>
119 </div>
120 <div style="float:left">
121 ${h.form(h.url('repo', repo_name=repo_name),method='delete')}
122 ${h.submit('remove_%s' % repo_name,_('delete'),class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo_name+"');")}
123 ${h.end_form()}
124 </div>
125 </div>
126 </%def>
127
119 128 <%def name="user_actions(user_id, username)">
120 129 ${h.form(h.url('delete_user', id=user_id),method='delete')}
121 130 ${h.submit('remove_',_('delete'),id="remove_user_%s" % user_id,
122 131 class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this user: %s') % username+"');")}
123 132 ${h.end_form()}
124 133 </%def>
125 134
126 135 <%def name="user_name(user_id, username)">
127 136 ${h.link_to(username,h.url('edit_user', id=user_id))}
128 137 </%def>
138
139 <%def name="toggle_follow(repo_id)">
140 <span id="follow_toggle_${repo_id}" class="following" title="${_('Stop following this repository')}"
141 onclick="javascript:toggleFollowingRepo(this, ${repo_id},'${str(h.get_token())}')">
142 </span>
143 </%def>
144
@@ -1,334 +1,337 b''
1 1 <%page args="parent" />
2 2 <div class="box">
3 3 <!-- box / title -->
4 4 <div class="title">
5 5 <h5>
6 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 7 </h5>
8 8 %if c.rhodecode_user.username != 'default':
9 9 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
10 10 <ul class="links">
11 11 <li>
12 12 %if c.group:
13 13 <span>${h.link_to(_('ADD REPOSITORY'),h.url('admin_settings_create_repository',parent_group=c.group.group_id))}</span>
14 14 %else:
15 15 <span>${h.link_to(_('ADD REPOSITORY'),h.url('admin_settings_create_repository'))}</span>
16 16 %endif
17 17 </li>
18 18 </ul>
19 19 %endif
20 20 %endif
21 21 </div>
22 22 <!-- end box / title -->
23 23 <div class="table">
24 24 % if c.groups:
25 25 <div id='groups_list_wrap' class="yui-skin-sam">
26 26 <table id="groups_list">
27 27 <thead>
28 28 <tr>
29 29 <th class="left"><a href="#">${_('Group name')}</a></th>
30 30 <th class="left"><a href="#">${_('Description')}</a></th>
31 31 ##<th class="left"><a href="#">${_('Number of repositories')}</a></th>
32 32 </tr>
33 33 </thead>
34 34
35 35 ## REPO GROUPS
36 36 % for gr in c.groups:
37 37 <tr>
38 38 <td>
39 39 <div style="white-space: nowrap">
40 40 <img class="icon" alt="${_('Repositories group')}" src="${h.url('/images/icons/database_link.png')}"/>
41 41 ${h.link_to(gr.name,url('repos_group_home',group_name=gr.group_name))}
42 42 </div>
43 43 </td>
44 44 %if c.visual.stylify_metatags:
45 45 <td>${h.urlify_text(h.desc_stylize(gr.group_description))}</td>
46 46 %else:
47 47 <td>${gr.group_description}</td>
48 48 %endif
49 49 ## this is commented out since for multi nested repos can be HEAVY!
50 50 ## in number of executed queries during traversing uncomment at will
51 51 ##<td><b>${gr.repositories_recursive_count}</b></td>
52 52 </tr>
53 53 % endfor
54 54
55 55 </table>
56 56 </div>
57 57 <div style="height: 20px"></div>
58 58 % endif
59 59 <div id="welcome" style="display:none;text-align:center">
60 60 <h1><a href="${h.url('home')}">${c.rhodecode_name} ${c.rhodecode_version}</a></h1>
61 61 </div>
62 62 <%cnt=0%>
63 63 <%namespace name="dt" file="/data_table/_dt_elements.html"/>
64 64 % if c.visual.lightweight_dashboard is False:
65 65 ## old full detailed version
66 66 <div id='repos_list_wrap' class="yui-skin-sam">
67 67 <table id="repos_list">
68 68 <thead>
69 69 <tr>
70 70 <th class="left"></th>
71 71 <th class="left">${_('Name')}</th>
72 72 <th class="left">${_('Description')}</th>
73 73 <th class="left">${_('Last change')}</th>
74 74 <th class="left">${_('Tip')}</th>
75 75 <th class="left">${_('Owner')}</th>
76 76 <th class="left">${_('RSS')}</th>
77 77 <th class="left">${_('Atom')}</th>
78 78 </tr>
79 79 </thead>
80 80 <tbody>
81 81 %for cnt,repo in enumerate(c.repos_list):
82 82 <tr class="parity${(cnt+1)%2}">
83 83 ##QUICK MENU
84 84 <td class="quick_repo_menu">
85 85 ${dt.quick_menu(repo['name'])}
86 86 </td>
87 87 ##REPO NAME AND ICONS
88 88 <td class="reponame">
89 89 ${dt.repo_name(repo['name'],repo['dbrepo']['repo_type'],repo['dbrepo']['private'],h.AttributeDict(repo['dbrepo_fork']),pageargs.get('short_repo_names'))}
90 90 </td>
91 91 ##DESCRIPTION
92 92 <td><span class="tooltip" title="${h.tooltip(repo['description'])}">
93 93 %if c.visual.stylify_metatags:
94 94 ${h.urlify_text(h.desc_stylize(h.truncate(repo['description'],60)))}</span>
95 95 %else:
96 96 ${h.truncate(repo['description'],60)}</span>
97 97 %endif
98 98 </td>
99 99 ##LAST CHANGE DATE
100 100 <td>
101 101 ${dt.last_change(repo['last_change'])}
102 102 </td>
103 103 ##LAST REVISION
104 104 <td>
105 105 ${dt.revision(repo['name'],repo['rev'],repo['tip'],repo['author'],repo['last_msg'])}
106 106 </td>
107 107 ##
108 108 <td title="${repo['contact']}">${h.person(repo['contact'])}</td>
109 109 <td>
110 110 ${dt.rss(repo['name'])}
111 111 </td>
112 112 <td>
113 113 ${dt.atom(repo['name'])}
114 114 </td>
115 115 </tr>
116 116 %endfor
117 117 </tbody>
118 118 </table>
119 119 </div>
120 120 % else:
121 121 ## lightweight version
122 122 <div class="yui-skin-sam" id="repos_list_wrap"></div>
123 123 <div id="user-paginator" style="padding: 0px 0px 0px 0px"></div>
124 124 % endif
125 125 </div>
126 126 </div>
127 127 % if c.visual.lightweight_dashboard is False:
128 128 <script>
129 129 YUD.get('repo_count').innerHTML = ${cnt+1 if cnt else 0};
130 var func = function(node){
131 return node.parentNode.parentNode.parentNode.parentNode;
132 }
133 130
134 131 // groups table sorting
135 132 var myColumnDefs = [
136 133 {key:"name",label:"${_('Group name')}",sortable:true,
137 134 sortOptions: { sortFunction: groupNameSort }},
138 135 {key:"desc",label:"${_('Description')}",sortable:true},
139 136 ];
140 137
141 138 var myDataSource = new YAHOO.util.DataSource(YUD.get("groups_list"));
142 139
143 140 myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
144 141 myDataSource.responseSchema = {
145 142 fields: [
146 143 {key:"name"},
147 144 {key:"desc"},
148 145 ]
149 146 };
150 147
151 148 var myDataTable = new YAHOO.widget.DataTable("groups_list_wrap", myColumnDefs, myDataSource,{
152 149 sortedBy:{key:"name",dir:"asc"},
153 150 paginator: new YAHOO.widget.Paginator({
154 151 rowsPerPage: 5,
155 152 alwaysVisible: false,
156 153 template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}",
157 154 pageLinks: 5,
158 155 containerClass: 'pagination-wh',
159 156 currentPageClass: 'pager_curpage',
160 157 pageLinkClass: 'pager_link',
161 158 nextPageLinkLabel: '&gt;',
162 159 previousPageLinkLabel: '&lt;',
163 160 firstPageLinkLabel: '&lt;&lt;',
164 161 lastPageLinkLabel: '&gt;&gt;',
165 162 containers:['user-paginator']
166 163 }),
167 164 MSG_SORTASC:"${_('Click to sort ascending')}",
168 165 MSG_SORTDESC:"${_('Click to sort descending')}"
169 166 });
170 167
171 168 // main table sorting
172 169 var myColumnDefs = [
173 170 {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
174 171 {key:"name",label:"${_('Name')}",sortable:true,
175 172 sortOptions: { sortFunction: nameSort }},
176 173 {key:"desc",label:"${_('Description')}",sortable:true},
177 174 {key:"last_change",label:"${_('Last Change')}",sortable:true,
178 175 sortOptions: { sortFunction: ageSort }},
179 176 {key:"tip",label:"${_('Tip')}",sortable:true,
180 177 sortOptions: { sortFunction: revisionSort }},
181 178 {key:"owner",label:"${_('Owner')}",sortable:true},
182 179 {key:"rss",label:"",sortable:false},
183 180 {key:"atom",label:"",sortable:false},
184 181 ];
185 182
186 183 var myDataSource = new YAHOO.util.DataSource(YUD.get("repos_list"));
187 184
188 185 myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
189 186
190 187 myDataSource.responseSchema = {
191 188 fields: [
192 189 {key:"menu"},
193 190 //{key:"raw_name"},
194 191 {key:"name"},
195 192 {key:"desc"},
196 193 {key:"last_change"},
197 194 {key:"tip"},
198 195 {key:"owner"},
199 196 {key:"rss"},
200 197 {key:"atom"},
201 198 ]
202 199 };
203 200
204 201 var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,
205 202 {
206 203 sortedBy:{key:"name",dir:"asc"},
207 204 MSG_SORTASC:"${_('Click to sort ascending')}",
208 205 MSG_SORTDESC:"${_('Click to sort descending')}",
209 206 MSG_EMPTY:"${_('No records found.')}",
210 207 MSG_ERROR:"${_('Data error.')}",
211 208 MSG_LOADING:"${_('Loading...')}",
212 209 }
213 210 );
214 211 myDataTable.subscribe('postRenderEvent',function(oArgs) {
215 212 tooltip_activate();
216 213 quick_repo_menu();
214 var func = function(node){
215 return node.parentNode.parentNode.parentNode.parentNode;
216 }
217 217 q_filter('q_filter',YUQ('div.table tr td a.repo_name'),func);
218 218 });
219 219
220 220 </script>
221 221 % else:
222 222 <script>
223 //var url = "${h.url('formatted_users', format='json')}";
224 223 var data = ${c.data|n};
225 224 var myDataSource = new YAHOO.util.DataSource(data);
226 225 myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
227 226
228 227 myDataSource.responseSchema = {
229 228 resultsList: "records",
230 229 fields: [
231 230 {key:"menu"},
232 231 {key:"raw_name"},
233 232 {key:"name"},
234 233 {key:"desc"},
235 234 {key:"last_change"},
236 {key: "tip"},
235 {key:"last_changeset"},
237 236 {key:"owner"},
238 237 {key:"rss"},
239 238 {key:"atom"},
240 239 ]
241 240 };
242 241 myDataSource.doBeforeCallback = function(req,raw,res,cb) {
243 242 // This is the filter function
244 243 var data = res.results || [],
245 244 filtered = [],
246 245 i,l;
247 246
248 247 if (req) {
249 248 req = req.toLowerCase();
250 249 for (i = 0; i<data.length; i++) {
251 250 var pos = data[i].raw_name.toLowerCase().indexOf(req)
252 251 if (pos != -1) {
253 252 filtered.push(data[i]);
254 253 }
255 254 }
256 255 res.results = filtered;
257 256 }
258 257 YUD.get('repo_count').innerHTML = res.results.length;
259 258 return res;
260 259 }
261 260
262 261 // main table sorting
263 262 var myColumnDefs = [
264 263 {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
265 264 {key:"name",label:"${_('Name')}",sortable:true,
266 265 sortOptions: { sortFunction: nameSort }},
267 266 {key:"desc",label:"${_('Description')}",sortable:true},
268 267 {key:"last_change",label:"${_('Last Change')}",sortable:true,
269 268 sortOptions: { sortFunction: ageSort }},
270 {key:"tip",label:"${_('Tip')}",sortable:true,
269 {key:"last_changeset",label:"${_('Tip')}",sortable:true,
271 270 sortOptions: { sortFunction: revisionSort }},
272 271 {key:"owner",label:"${_('Owner')}",sortable:true},
273 272 {key:"rss",label:"",sortable:false},
274 273 {key:"atom",label:"",sortable:false},
275 274 ];
276 275
277 276 var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{
278 277 sortedBy:{key:"name",dir:"asc"},
279 278 paginator: new YAHOO.widget.Paginator({
280 279 rowsPerPage: ${c.visual.lightweight_dashboard_items},
281 280 alwaysVisible: false,
282 281 template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}",
283 282 pageLinks: 5,
284 283 containerClass: 'pagination-wh',
285 284 currentPageClass: 'pager_curpage',
286 285 pageLinkClass: 'pager_link',
287 286 nextPageLinkLabel: '&gt;',
288 287 previousPageLinkLabel: '&lt;',
289 288 firstPageLinkLabel: '&lt;&lt;',
290 289 lastPageLinkLabel: '&gt;&gt;',
291 290 containers:['user-paginator']
292 291 }),
293 292
294 293 MSG_SORTASC:"${_('Click to sort ascending')}",
295 294 MSG_SORTDESC:"${_('Click to sort descending')}",
296 295 MSG_EMPTY:"${_('No records found.')}",
297 296 MSG_ERROR:"${_('Data error.')}",
298 297 MSG_LOADING:"${_('Loading...')}",
299 298 }
300 299 );
301 300 myDataTable.subscribe('postRenderEvent',function(oArgs) {
302 301 tooltip_activate();
303 302 quick_repo_menu();
304 303 });
305 304
306 305 var filterTimeout = null;
307 306
308 307 updateFilter = function () {
309 308 // Reset timeout
310 309 filterTimeout = null;
311 310
312 311 // Reset sort
313 312 var state = myDataTable.getState();
314 313 state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC};
315 314
316 315 // Get filtered data
317 316 myDataSource.sendRequest(YUD.get('q_filter').value,{
318 317 success : myDataTable.onDataReturnInitializeTable,
319 318 failure : myDataTable.onDataReturnInitializeTable,
320 319 scope : myDataTable,
321 320 argument: state
322 321 });
323 322
324 323 };
325 324 YUE.on('q_filter','click',function(){
325 if(!YUD.hasClass('q_filter', 'loaded')){
326 326 YUD.get('q_filter').value = '';
327 //TODO: load here full list later to do search within groups
328 YUD.addClass('q_filter', 'loaded');
329 }
327 330 });
328 331
329 332 YUE.on('q_filter','keyup',function (e) {
330 333 clearTimeout(filterTimeout);
331 334 filterTimeout = setTimeout(updateFilter,600);
332 335 });
333 336 </script>
334 337 % endif
@@ -1,241 +1,375 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3 <%def name="title()">
4 4 ${_('Journal')} - ${c.rhodecode_name}
5 5 </%def>
6 6 <%def name="breadcrumbs()">
7 7 <h5>
8 8 <form id="filter_form">
9 9 <input class="q_filter_box ${'' if c.search_term else 'initial'}" id="j_filter" size="15" type="text" name="filter" value="${c.search_term or _('quick filter...')}"/>
10 10 <span class="tooltip" title="${h.tooltip(h.journal_filter_help())}">?</span>
11 11 <input type='submit' value="${_('filter')}" class="ui-btn" style="padding:0px 2px 0px 2px;margin:0px"/>
12 12 ${_('journal')} - ${ungettext('%s entry', '%s entries', c.journal_pager.item_count) % (c.journal_pager.item_count)}
13 13 </form>
14 14 ${h.end_form()}
15 15 </h5>
16 16 </%def>
17 17 <%def name="page_nav()">
18 18 ${self.menu('home')}
19 19 </%def>
20 20 <%def name="head_extra()">
21 21 <link href="${h.url('journal_atom', api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('ATOM journal feed')}" type="application/atom+xml" />
22 22 <link href="${h.url('journal_rss', api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('RSS journal feed')}" type="application/rss+xml" />
23 23 </%def>
24 24 <%def name="main()">
25 25
26 26 <div class="box box-left">
27 27 <!-- box / title -->
28 28 <div class="title">
29 29 ${self.breadcrumbs()}
30 30 <ul class="links">
31 31 <li>
32 32 <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>
33 33 </li>
34 34 <li>
35 35 <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>
36 36 </li>
37 37 <li>
38 38 <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>
39 39 </li>
40 40 </ul>
41 41 </div>
42 42 <div id="journal">${c.journal_data}</div>
43 43 </div>
44 44 <div class="box box-right">
45 45 <!-- box / title -->
46
46 47 <div class="title">
47 48 <h5>
48 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}"/>
49 <a id="show_watched" class="link-white" href="#watched">${_('Watched')}</a> / <a id="show_my" class="link-white" href="#my">${_('My repos')}</a>
49 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${_('quick filter...')}" style="display: none"/>
50 <input class="q_filter_box" id="q_filter_watched" size="15" type="text" name="filter" value="${_('quick filter...')}" style="display: none"/>
50 51 </h5>
51 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
52 <ul class="links">
52 <ul class="links" style="color:#DADADA">
53 53 <li>
54 <span>${h.link_to(_('ADD'),h.url('admin_settings_create_repository'))}</span>
54 <span><a id="show_watched" class="link-white current" href="#watched">${_('Watched')}</a> </span>
55 55 </li>
56 </ul>
56 <li>
57 <span><a id="show_my" class="link-white" href="#my">${_('My repos')}</a> </span>
58 </li>
59 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
60 <li>
61 <span>${h.link_to(_('Add repo'),h.url('admin_settings_create_repository'))}</span>
62 </li>
57 63 %endif
58 </div>
59 <!-- end box / title -->
60 <div id="my" class="table" style="display:none">
61 ## loaded via AJAX
62 ${_('Loading...')}
64 </ul>
63 65 </div>
64 66
65 <div id="watched" class="table">
66 %if c.following:
67 <table>
68 <thead>
69 <tr>
70 <th class="left">${_('Name')}</th>
71 </thead>
72 <tbody>
73 %for entry in c.following:
74 <tr>
75 <td>
76 %if entry.follows_user_id:
77 <img title="${_('following user')}" alt="${_('user')}" src="${h.url('/images/icons/user.png')}"/>
78 ${entry.follows_user.full_contact}
79 %endif
80
81 %if entry.follows_repo_id:
82 <div style="float:right;padding-right:5px">
83 <span id="follow_toggle_${entry.follows_repository.repo_id}" class="following" title="${_('Stop following this repository')}"
84 onclick="javascript:toggleFollowingRepo(this,${entry.follows_repository.repo_id},'${str(h.get_token())}')">
85 </span>
67 <!-- end box / title -->
68 <div id="my_container" style="display:none">
69 <div class="table yui-skin-sam" id="repos_list_wrap"></div>
70 <div id="user-paginator" style="padding: 0px 0px 0px 20px"></div>
86 71 </div>
87 72
88 %if h.is_hg(entry.follows_repository):
89 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
90 %elif h.is_git(entry.follows_repository):
91 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
92 %endif
93
94 %if entry.follows_repository.private and c.visual.show_private_icon:
95 <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
96 %elif not entry.follows_repository.private and c.visual.show_public_icon:
97 <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
98 %endif
99 <span class="watched_repo">
100 ${h.link_to(entry.follows_repository.repo_name,h.url('summary_home',repo_name=entry.follows_repository.repo_name))}
101 </span>
102 %endif
103 </td>
104 </tr>
105 %endfor
106 </tbody>
107 </table>
108 %else:
109 <div style="padding:5px 0px 10px 0px;">
110 ${_('You are not following any users or repositories')}
111 </div>
112 %endif
73 <div id="watched_container">
74 <div class="table yui-skin-sam" id="watched_repos_list_wrap"></div>
75 <div id="watched-user-paginator" style="padding: 0px 0px 0px 20px"></div>
113 76 </div>
114 77 </div>
115 78
116 79 <script type="text/javascript">
117 80
118 81 YUE.on('j_filter','click',function(){
119 82 var jfilter = YUD.get('j_filter');
120 83 if(YUD.hasClass(jfilter, 'initial')){
121 84 jfilter.value = '';
122 85 }
123 86 });
124 87 var fix_j_filter_width = function(len){
125 88 YUD.setStyle(YUD.get('j_filter'),'width',Math.max(80, len*6.50)+'px');
126 89 }
127 90 YUE.on('j_filter','keyup',function(){
128 91 fix_j_filter_width(YUD.get('j_filter').value.length);
129 92 });
130 93 YUE.on('filter_form','submit',function(e){
131 94 YUE.preventDefault(e)
132 95 var val = YUD.get('j_filter').value;
133 96 window.location = "${url.current(filter='__FILTER__')}".replace('__FILTER__',val);
134 97 });
135 98 fix_j_filter_width(YUD.get('j_filter').value.length);
136 99
137 var show_my = function(e){
138 YUD.setStyle('watched','display','none');
139 YUD.setStyle('my','display','');
140
141 var url = "${h.url('admin_settings_my_repos')}";
142 ypjax(url, 'my', function(){
100 YUE.on('refresh','click',function(e){
101 ypjax("${h.url.current(filter=c.search_term)}","journal",function(){
102 show_more_event();
143 103 tooltip_activate();
144 quick_repo_menu();
145 var nodes = YUQ('#my tr td a.repo_name');
146 var func = function(node){
147 return node.parentNode.parentNode.parentNode;
148 }
149 q_filter('q_filter',nodes,func);
104 show_changeset_tooltip();
105 });
106 YUE.preventDefault(e);
150 107 });
151 108
109 var show_my = function(e){
110 YUD.setStyle('watched_container','display','none');
111 YUD.setStyle('my_container','display','');
112 YUD.setStyle('q_filter','display','');
113 YUD.setStyle('q_filter_watched','display','none');
114
115 YUD.addClass('show_my', 'current');
116 YUD.removeClass('show_watched','current');
117
118 if(!YUD.hasClass('show_my', 'loaded')){
119 table_renderer(${c.data |n});
120 YUD.addClass('show_my', 'loaded');
121 }
152 122 }
153 123 YUE.on('show_my','click',function(e){
154 124 show_my(e);
155 125 })
156 126 var show_watched = function(e){
157 YUD.setStyle('my','display','none');
158 YUD.setStyle('watched','display','');
159 var nodes = YUQ('#watched .watched_repo a');
127 YUD.setStyle('my_container','display','none');
128 YUD.setStyle('watched_container','display','');
129 YUD.setStyle('q_filter_watched','display','');
130 YUD.setStyle('q_filter','display','none');
131
132 YUD.addClass('show_watched', 'current');
133 YUD.removeClass('show_my','current');
134 if(!YUD.hasClass('show_watched', 'loaded')){
135 watched_renderer(${c.watched_data |n});
136 YUD.addClass('show_watched', 'loaded');
137 }
138
139 return
140 var nodes = YUQ('#watched_container .watched_repo a');
160 141 var target = 'q_filter';
161 142 var func = function(node){
162 143 return node.parentNode.parentNode;
163 144 }
164 145 q_filter(target,nodes,func);
165 146 }
166 147 YUE.on('show_watched','click',function(e){
167 148 show_watched(e);
168 149 })
169 150 //init watched
170 151 show_watched();
171 152
172 153 var tabs = {
173 154 'watched': show_watched,
174 155 'my': show_my,
175 156 }
176 157 var url = location.href.split('#');
177 158 if (url[1]) {
178 159 //We have a hash
179 160 var tabHash = url[1];
180 161 var func = tabs[tabHash]
181 162 if (func){
182 163 func();
183 164 }
184 165 }
166 function watched_renderer(data){
167 var myDataSource = new YAHOO.util.DataSource(data);
168 myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
185 169
186 YUE.on('refresh','click',function(e){
187 ypjax("${h.url.current(filter=c.search_term)}","journal",function(){
188 show_more_event();
189 tooltip_activate();
190 show_changeset_tooltip();
191 });
192 YUE.preventDefault(e);
193 });
170 myDataSource.responseSchema = {
171 resultsList: "records",
172 fields: [
173 {key:"menu"},
174 {key:"raw_name"},
175 {key:"name"},
176 {key:"last_changeset"},
177 {key:"action"},
178 ]
179 };
180 myDataSource.doBeforeCallback = function(req,raw,res,cb) {
181 // This is the filter function
182 var data = res.results || [],
183 filtered = [],
184 i,l;
194 185
195
186 if (req) {
187 req = req.toLowerCase();
188 for (i = 0; i<data.length; i++) {
189 var pos = data[i].raw_name.toLowerCase().indexOf(req)
190 if (pos != -1) {
191 filtered.push(data[i]);
192 }
193 }
194 res.results = filtered;
195 }
196 return res;
197 }
196 198 // main table sorting
197 199 var myColumnDefs = [
198 200 {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
199 201 {key:"name",label:"${_('Name')}",sortable:true,
200 202 sortOptions: { sortFunction: nameSort }},
201 {key:"tip",label:"${_('Tip')}",sortable:true,
203 {key:"last_changeset",label:"${_('Tip')}",sortable:true,
202 204 sortOptions: { sortFunction: revisionSort }},
203 {key:"action1",label:"",sortable:false},
204 {key:"action2",label:"",sortable:false},
205 {key:"action",label:"${_('Action')}",sortable:false},
205 206 ];
206 207
207 var myDataSource = new YAHOO.util.DataSource(YUD.get("repos_list"));
208
209 myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
208 var myDataTable = new YAHOO.widget.DataTable("watched_repos_list_wrap", myColumnDefs, myDataSource,{
209 sortedBy:{key:"name",dir:"asc"},
210 paginator: new YAHOO.widget.Paginator({
211 rowsPerPage: 25,
212 alwaysVisible: false,
213 template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}",
214 pageLinks: 5,
215 containerClass: 'pagination-wh',
216 currentPageClass: 'pager_curpage',
217 pageLinkClass: 'pager_link',
218 nextPageLinkLabel: '&gt;',
219 previousPageLinkLabel: '&lt;',
220 firstPageLinkLabel: '&lt;&lt;',
221 lastPageLinkLabel: '&gt;&gt;',
222 containers:['watched-user-paginator']
223 }),
210 224
211 myDataSource.responseSchema = {
212 fields: [
213 {key:"menu"},
214 {key:"name"},
215 {key:"tip"},
216 {key:"action1"},
217 {key:"action2"}
218 ]
219 };
220
221 var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,
222 {
223 sortedBy:{key:"name",dir:"asc"},
224 225 MSG_SORTASC:"${_('Click to sort ascending')}",
225 226 MSG_SORTDESC:"${_('Click to sort descending')}",
226 227 MSG_EMPTY:"${_('No records found.')}",
227 228 MSG_ERROR:"${_('Data error.')}",
228 229 MSG_LOADING:"${_('Loading...')}",
229 230 }
230 231 );
231 232 myDataTable.subscribe('postRenderEvent',function(oArgs) {
232 233 tooltip_activate();
233 234 quick_repo_menu();
234 var func = function(node){
235 return node.parentNode.parentNode.parentNode.parentNode;
235 });
236
237 var filterTimeout = null;
238
239 updateFilter = function () {
240 // Reset timeout
241 filterTimeout = null;
242
243 // Reset sort
244 var state = myDataTable.getState();
245 state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC};
246
247 // Get filtered data
248 myDataSource.sendRequest(YUD.get('q_filter_watched').value,{
249 success : myDataTable.onDataReturnInitializeTable,
250 failure : myDataTable.onDataReturnInitializeTable,
251 scope : myDataTable,
252 argument: state
253 });
254
255 };
256 YUE.on('q_filter_watched','click',function(){
257 if(!YUD.hasClass('q_filter_watched', 'loaded')){
258 YUD.get('q_filter_watched').value = '';
259 //TODO: load here full list later to do search within groups
260 YUD.addClass('q_filter_watched', 'loaded');
261 }
262 });
263
264 YUE.on('q_filter_watched','keyup',function (e) {
265 clearTimeout(filterTimeout);
266 filterTimeout = setTimeout(updateFilter,600);
267 });
268 }
269
270 function table_renderer(data){
271 var myDataSource = new YAHOO.util.DataSource(data);
272 myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
273
274 myDataSource.responseSchema = {
275 resultsList: "records",
276 fields: [
277 {key:"menu"},
278 {key:"raw_name"},
279 {key:"name"},
280 {key:"last_changeset"},
281 {key:"action"},
282 ]
283 };
284 myDataSource.doBeforeCallback = function(req,raw,res,cb) {
285 // This is the filter function
286 var data = res.results || [],
287 filtered = [],
288 i,l;
289
290 if (req) {
291 req = req.toLowerCase();
292 for (i = 0; i<data.length; i++) {
293 var pos = data[i].raw_name.toLowerCase().indexOf(req)
294 if (pos != -1) {
295 filtered.push(data[i]);
296 }
297 }
298 res.results = filtered;
299 }
300 return res;
236 301 }
237 q_filter('q_filter',YUQ('#my tr td a.repo_name'),func);
302 // main table sorting
303 var myColumnDefs = [
304 {key:"menu",label:"",sortable:false,className:"quick_repo_menu hidden"},
305 {key:"name",label:"${_('Name')}",sortable:true,
306 sortOptions: { sortFunction: nameSort }},
307 {key:"last_changeset",label:"${_('Tip')}",sortable:true,
308 sortOptions: { sortFunction: revisionSort }},
309 {key:"action",label:"${_('Action')}",sortable:false},
310 ];
311
312 var myDataTable = new YAHOO.widget.DataTable("repos_list_wrap", myColumnDefs, myDataSource,{
313 sortedBy:{key:"name",dir:"asc"},
314 paginator: new YAHOO.widget.Paginator({
315 rowsPerPage: 25,
316 alwaysVisible: false,
317 template : "{PreviousPageLink} {FirstPageLink} {PageLinks} {LastPageLink} {NextPageLink}",
318 pageLinks: 5,
319 containerClass: 'pagination-wh',
320 currentPageClass: 'pager_curpage',
321 pageLinkClass: 'pager_link',
322 nextPageLinkLabel: '&gt;',
323 previousPageLinkLabel: '&lt;',
324 firstPageLinkLabel: '&lt;&lt;',
325 lastPageLinkLabel: '&gt;&gt;',
326 containers:['user-paginator']
327 }),
328
329 MSG_SORTASC:"${_('Click to sort ascending')}",
330 MSG_SORTDESC:"${_('Click to sort descending')}",
331 MSG_EMPTY:"${_('No records found.')}",
332 MSG_ERROR:"${_('Data error.')}",
333 MSG_LOADING:"${_('Loading...')}",
334 }
335 );
336 myDataTable.subscribe('postRenderEvent',function(oArgs) {
337 tooltip_activate();
338 quick_repo_menu();
238 339 });
239 340
341 var filterTimeout = null;
342
343 updateFilter = function () {
344 // Reset timeout
345 filterTimeout = null;
346
347 // Reset sort
348 var state = myDataTable.getState();
349 state.sortedBy = {key:'name', dir:YAHOO.widget.DataTable.CLASS_ASC};
350
351 // Get filtered data
352 myDataSource.sendRequest(YUD.get('q_filter').value,{
353 success : myDataTable.onDataReturnInitializeTable,
354 failure : myDataTable.onDataReturnInitializeTable,
355 scope : myDataTable,
356 argument: state
357 });
358
359 };
360 YUE.on('q_filter','click',function(){
361 if(!YUD.hasClass('q_filter', 'loaded')){
362 YUD.get('q_filter').value = '';
363 //TODO: load here full list later to do search within groups
364 YUD.addClass('q_filter', 'loaded');
365 }
366 });
367
368 YUE.on('q_filter','keyup',function (e) {
369 clearTimeout(filterTimeout);
370 filterTimeout = setTimeout(updateFilter,600);
371 });
372 }
373
240 374 </script>
241 375 </%def>
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now