##// END OF EJS Templates
coding style: fix trailing and leading spaces and tabs
Mads Kiilerich -
r3267:7b74079b beta
parent child Browse files
Show More
@@ -1,981 +1,981 b''
1 1 .. _api:
2 2
3 3 ===
4 4 API
5 5 ===
6 6
7 7
8 8 Starting from RhodeCode version 1.2 a simple API was implemented.
9 9 There's a single schema for calling all api methods. API is implemented
10 10 with JSON protocol both ways. An url to send API request to RhodeCode is
11 11 <your_server>/_admin/api
12 12
13 13 API ACCESS FOR WEB VIEWS
14 14 ++++++++++++++++++++++++
15 15
16 16 API access can also be turned on for each web view in RhodeCode that is
17 17 decorated with `@LoginRequired` decorator. To enable API access simple change
18 18 the standard login decorator to `@LoginRequired(api_access=True)`.
19 19 After this change, a rhodecode view can be accessed without login by adding a
20 20 GET parameter `?api_key=<api_key>` to url. By default this is only
21 21 enabled on RSS/ATOM feed views.
22 22
23 23
24 24 API ACCESS
25 25 ++++++++++
26 26
27 27 All clients are required to send JSON-RPC spec JSON data::
28 28
29 29 {
30 30 "id:"<id>",
31 31 "api_key":"<api_key>",
32 32 "method":"<method_name>",
33 33 "args":{"<arg_key>":"<arg_val>"}
34 34 }
35 35
36 36 Example call for autopulling remotes repos using curl::
37 37 curl https://server.com/_admin/api -X POST -H 'content-type:text/plain' --data-binary '{"id":1,"api_key":"xe7cdb2v278e4evbdf5vs04v832v0efvcbcve4a3","method":"pull","args":{"repo":"CPython"}}'
38 38
39 39 Simply provide
40 40 - *id* A value of any type, which is used to match the response with the request that it is replying to.
41 41 - *api_key* for access and permission validation.
42 42 - *method* is name of method to call
43 43 - *args* is an key:value list of arguments to pass to method
44 44
45 45 .. note::
46 46
47 47 api_key can be found in your user account page
48 48
49 49
50 50 RhodeCode API will return always a JSON-RPC response::
51 51
52 52 {
53 53 "id":<id>, # matching id sent by request
54 54 "result": "<result>"|null, # JSON formatted result, null if any errors
55 55 "error": "null"|<error_message> # JSON formatted error (if any)
56 56 }
57 57
58 58 All responses from API will be `HTTP/1.0 200 OK`, if there's an error while
59 59 calling api *error* key from response will contain failure description
60 60 and result will be null.
61 61
62 62
63 63 API CLIENT
64 64 ++++++++++
65 65
66 66 From version 1.4 RhodeCode adds a script that allows to easily
67 67 communicate with API. After installing RhodeCode a `rhodecode-api` script
68 68 will be available.
69 69
70 70 To get started quickly simply run::
71 71
72 72 rhodecode-api _create_config --apikey=<youapikey> --apihost=<rhodecode host>
73 73
74 74 This will create a file named .config in the directory you executed it storing
75 75 json config file with credentials. You can skip this step and always provide
76 76 both of the arguments to be able to communicate with server
77 77
78 78
79 79 after that simply run any api command for example get_repo::
80 80
81 81 rhodecode-api get_repo
82 82
83 83 calling {"api_key": "<apikey>", "id": 75, "args": {}, "method": "get_repo"} to http://127.0.0.1:5000
84 84 rhodecode said:
85 85 {'error': 'Missing non optional `repoid` arg in JSON DATA',
86 86 'id': 75,
87 87 'result': None}
88 88
89 89 Ups looks like we forgot to add an argument
90 90
91 91 Let's try again now giving the repoid as parameters::
92 92
93 93 rhodecode-api get_repo repoid:rhodecode
94 94
95 95 calling {"api_key": "<apikey>", "id": 39, "args": {"repoid": "rhodecode"}, "method": "get_repo"} to http://127.0.0.1:5000
96 96 rhodecode said:
97 97 {'error': None,
98 98 'id': 39,
99 99 'result': <json data...>}
100 100
101 101
102 102
103 103 API METHODS
104 104 +++++++++++
105 105
106 106
107 107 pull
108 108 ----
109 109
110 110 Pulls given repo from remote location. Can be used to automatically keep
111 111 remote repos up to date. This command can be executed only using api_key
112 112 belonging to user with admin rights
113 113
114 114 INPUT::
115 115
116 116 id : <id_for_response>
117 117 api_key : "<api_key>"
118 118 method : "pull"
119 119 args : {
120 120 "repoid" : "<reponame or repo_id>"
121 121 }
122 122
123 123 OUTPUT::
124 124
125 125 id : <id_given_in_input>
126 126 result : "Pulled from `<reponame>`"
127 127 error : null
128 128
129 129
130 130 rescan_repos
131 131 ------------
132 132
133 133 Dispatch rescan repositories action. If remove_obsolete is set
134 134 RhodeCode will delete repos that are in database but not in the filesystem.
135 135 This command can be executed only using api_key belonging to user with admin
136 136 rights.
137 137
138 138 INPUT::
139 139
140 140 id : <id_for_response>
141 141 api_key : "<api_key>"
142 142 method : "rescan_repos"
143 143 args : {
144 144 "remove_obsolete" : "<boolean = Optional(False)>"
145 145 }
146 146
147 147 OUTPUT::
148 148
149 149 id : <id_given_in_input>
150 150 result : "{'added': [<list of names of added repos>],
151 151 'removed': [<list of names of removed repos>]}"
152 152 error : null
153 153
154 154
155 155 invalidate_cache
156 156 ----------------
157 157
158 158 Invalidate cache for repository.
159 159 This command can be executed only using api_key belonging to user with admin
160 160 rights or regular user that have write or admin or write access to repository.
161 161
162 162 INPUT::
163 163
164 164 id : <id_for_response>
165 165 api_key : "<api_key>"
166 166 method : "invalidate_cache"
167 167 args : {
168 168 "repoid" : "<reponame or repo_id>"
169 169 }
170 170
171 171 OUTPUT::
172 172
173 173 id : <id_given_in_input>
174 174 result : "Cache for repository `<reponame>` was invalidated: invalidated cache keys: <list_of_cache_keys>"
175 175 error : null
176 176
177 177 lock
178 178 ----
179 179
180 180 Set locking state on given repository by given user. If userid param is skipped
181 181 , then it is set to id of user whos calling this method.
182 182 This command can be executed only using api_key belonging to user with admin
183 183 rights or regular user that have admin or write access to repository.
184 184
185 185 INPUT::
186 186
187 187 id : <id_for_response>
188 188 api_key : "<api_key>"
189 189 method : "lock"
190 190 args : {
191 191 "repoid" : "<reponame or repo_id>"
192 192 "userid" : "<user_id or username = Optional(=apiuser)>",
193 193 "locked" : "<bool true|false>"
194 194 }
195 195
196 196 OUTPUT::
197 197
198 198 id : <id_given_in_input>
199 199 result : "User `<username>` set lock state for repo `<reponame>` to `true|false`"
200 200 error : null
201 201
202 202
203 203 show_ip
204 204 -------
205 205
206 206 Shows IP address as seen from RhodeCode server, together with all
207 207 defined IP addresses for given user.
208 208 This command can be executed only using api_key belonging to user with admin
209 209 rights.
210 210
211 211 INPUT::
212 212
213 213 id : <id_for_response>
214 214 api_key : "<api_key>"
215 215 method : "show_ip"
216 216 args : {
217 217 "userid" : "<user_id or username>",
218 218 }
219 219
220 220 OUTPUT::
221 221
222 222 id : <id_given_in_input>
223 223 result : {
224 224 "ip_addr_server": <ip_from_clien>",
225 225 "user_ips": [
226 226 {
227 227 "ip_addr": "<ip_with_mask>",
228 228 "ip_range": ["<start_ip>", "<end_ip>"],
229 229 },
230 230 ...
231 231 ]
232 232 }
233 233
234 234 error : null
235 235
236 236
237 237 get_user
238 238 --------
239 239
240 240 Get's an user by username or user_id, Returns empty result if user is not found.
241 241 If userid param is skipped it is set to id of user who is calling this method.
242 242 This command can be executed only using api_key belonging to user with admin
243 243 rights, or regular users that cannot specify different userid than theirs
244 244
245 245
246 246 INPUT::
247 247
248 248 id : <id_for_response>
249 249 api_key : "<api_key>"
250 250 method : "get_user"
251 251 args : {
252 252 "userid" : "<username or user_id Optional(=apiuser)>"
253 253 }
254 254
255 255 OUTPUT::
256 256
257 257 id : <id_given_in_input>
258 258 result: None if user does not exist or
259 259 {
260 260 "user_id" : "<user_id>",
261 261 "api_key" : "<api_key>",
262 262 "username" : "<username>",
263 263 "firstname": "<firstname>",
264 264 "lastname" : "<lastname>",
265 265 "email" : "<email>",
266 266 "emails": "<list_of_all_additional_emails>",
267 267 "ip_addresses": "<list_of_ip_addresses_for_user>",
268 268 "active" : "<bool>",
269 269 "admin" :Β  "<bool>",
270 270 "ldap_dn" : "<ldap_dn>",
271 271 "last_login": "<last_login>",
272 272 "permissions": {
273 273 "global": ["hg.create.repository",
274 274 "repository.read",
275 275 "hg.register.manual_activate"],
276 276 "repositories": {"repo1": "repository.none"},
277 277 "repositories_groups": {"Group1": "group.read"}
278 278 },
279 279 }
280 280
281 281 error: null
282 282
283 283
284 284 get_users
285 285 ---------
286 286
287 287 Lists all existing users. This command can be executed only using api_key
288 288 belonging to user with admin rights.
289 289
290 290
291 291 INPUT::
292 292
293 293 id : <id_for_response>
294 294 api_key : "<api_key>"
295 295 method : "get_users"
296 296 args : { }
297 297
298 298 OUTPUT::
299 299
300 300 id : <id_given_in_input>
301 301 result: [
302 302 {
303 303 "user_id" : "<user_id>",
304 304 "username" : "<username>",
305 305 "firstname": "<firstname>",
306 306 "lastname" : "<lastname>",
307 307 "email" : "<email>",
308 308 "emails": "<list_of_all_additional_emails>",
309 309 "ip_addresses": "<list_of_ip_addresses_for_user>",
310 310 "active" : "<bool>",
311 311 "admin" :Β  "<bool>",
312 312 "ldap_dn" : "<ldap_dn>",
313 313 "last_login": "<last_login>",
314 314 },
315 …
315 …
316 316 ]
317 317 error: null
318 318
319 319
320 320 create_user
321 321 -----------
322 322
323 323 Creates new user. This command can
324 324 be executed only using api_key belonging to user with admin rights.
325 325
326 326
327 327 INPUT::
328 328
329 329 id : <id_for_response>
330 330 api_key : "<api_key>"
331 331 method : "create_user"
332 332 args : {
333 333 "username" : "<username>",
334 334 "email" : "<useremail>",
335 335 "password" : "<password>",
336 336 "firstname" : "<firstname> = Optional(None)",
337 337 "lastname" : "<lastname> = Optional(None)",
338 338 "active" : "<bool> = Optional(True)",
339 339 "admin" : "<bool> = Optional(False)",
340 340 "ldap_dn" : "<ldap_dn> = Optional(None)"
341 341 }
342 342
343 343 OUTPUT::
344 344
345 345 id : <id_given_in_input>
346 346 result: {
347 347 "msg" : "created new user `<username>`",
348 348 "user": {
349 349 "user_id" : "<user_id>",
350 350 "username" : "<username>",
351 351 "firstname": "<firstname>",
352 352 "lastname" : "<lastname>",
353 353 "email" : "<email>",
354 354 "emails": "<list_of_all_additional_emails>",
355 355 "active" : "<bool>",
356 356 "admin" :Β  "<bool>",
357 357 "ldap_dn" : "<ldap_dn>",
358 358 "last_login": "<last_login>",
359 359 },
360 360 }
361 361 error: null
362 362
363 363
364 364 update_user
365 365 -----------
366 366
367 367 updates given user if such user exists. This command can
368 368 be executed only using api_key belonging to user with admin rights.
369 369
370 370
371 371 INPUT::
372 372
373 373 id : <id_for_response>
374 374 api_key : "<api_key>"
375 375 method : "update_user"
376 376 args : {
377 377 "userid" : "<user_id or username>",
378 378 "username" : "<username> = Optional(None)",
379 379 "email" : "<useremail> = Optional(None)",
380 380 "password" : "<password> = Optional(None)",
381 381 "firstname" : "<firstname> = Optional(None)",
382 382 "lastname" : "<lastname> = Optional(None)",
383 383 "active" : "<bool> = Optional(None)",
384 384 "admin" : "<bool> = Optional(None)",
385 385 "ldap_dn" : "<ldap_dn> = Optional(None)"
386 386 }
387 387
388 388 OUTPUT::
389 389
390 390 id : <id_given_in_input>
391 391 result: {
392 392 "msg" : "updated user ID:<userid> <username>",
393 393 "user": {
394 394 "user_id" : "<user_id>",
395 395 "username" : "<username>",
396 396 "firstname": "<firstname>",
397 397 "lastname" : "<lastname>",
398 398 "email" : "<email>",
399 399 "emails": "<list_of_all_additional_emails>",
400 400 "active" : "<bool>",
401 401 "admin" :Β  "<bool>",
402 402 "ldap_dn" : "<ldap_dn>",
403 403 "last_login": "<last_login>",
404 404 },
405 405 }
406 406 error: null
407 407
408 408
409 409 delete_user
410 410 -----------
411 411
412 412
413 413 deletes givenuser if such user exists. This command can
414 414 be executed only using api_key belonging to user with admin rights.
415 415
416 416
417 417 INPUT::
418 418
419 419 id : <id_for_response>
420 420 api_key : "<api_key>"
421 421 method : "delete_user"
422 422 args : {
423 423 "userid" : "<user_id or username>",
424 424 }
425 425
426 426 OUTPUT::
427 427
428 428 id : <id_given_in_input>
429 429 result: {
430 430 "msg" : "deleted user ID:<userid> <username>",
431 431 "user": null
432 432 }
433 433 error: null
434 434
435 435
436 436 get_users_group
437 437 ---------------
438 438
439 439 Gets an existing users group. This command can be executed only using api_key
440 440 belonging to user with admin rights.
441 441
442 442
443 443 INPUT::
444 444
445 445 id : <id_for_response>
446 446 api_key : "<api_key>"
447 447 method : "get_users_group"
448 448 args : {
449 449 "usersgroupid" : "<users group id or name>"
450 450 }
451 451
452 452 OUTPUT::
453 453
454 454 id : <id_given_in_input>
455 455 result : None if group not exist
456 456 {
457 457 "users_group_id" : "<id>",
458 458 "group_name" : "<groupname>",
459 459 "active": "<bool>",
460 460 "members" : [
461 461 {
462 462 "user_id" : "<user_id>",
463 463 "username" : "<username>",
464 464 "firstname": "<firstname>",
465 465 "lastname" : "<lastname>",
466 466 "email" : "<email>",
467 467 "emails": "<list_of_all_additional_emails>",
468 468 "active" : "<bool>",
469 469 "admin" :Β  "<bool>",
470 470 "ldap_dn" : "<ldap_dn>",
471 471 "last_login": "<last_login>",
472 472 },
473 473 …
474 474 ]
475 475 }
476 476 error : null
477 477
478 478
479 479 get_users_groups
480 480 ----------------
481 481
482 482 Lists all existing users groups. This command can be executed only using
483 483 api_key belonging to user with admin rights.
484 484
485 485
486 486 INPUT::
487 487
488 488 id : <id_for_response>
489 489 api_key : "<api_key>"
490 490 method : "get_users_groups"
491 491 args : { }
492 492
493 493 OUTPUT::
494 494
495 495 id : <id_given_in_input>
496 496 result : [
497 497 {
498 498 "users_group_id" : "<id>",
499 499 "group_name" : "<groupname>",
500 500 "active": "<bool>",
501 501 },
502 502 …
503 503 ]
504 504 error : null
505 505
506 506
507 507 create_users_group
508 508 ------------------
509 509
510 510 Creates new users group. This command can be executed only using api_key
511 511 belonging to user with admin rights
512 512
513 513
514 514 INPUT::
515 515
516 516 id : <id_for_response>
517 517 api_key : "<api_key>"
518 518 method : "create_users_group"
519 519 args: {
520 520 "group_name": "<groupname>",
521 521 "active":"<bool> = Optional(True)"
522 522 }
523 523
524 524 OUTPUT::
525 525
526 526 id : <id_given_in_input>
527 527 result: {
528 528 "msg": "created new users group `<groupname>`",
529 529 "users_group": {
530 530 "users_group_id" : "<id>",
531 531 "group_name" : "<groupname>",
532 532 "active": "<bool>",
533 533 },
534 534 }
535 535 error: null
536 536
537 537
538 538 add_user_to_users_group
539 539 -----------------------
540 540
541 541 Adds a user to a users group. If user exists in that group success will be
542 542 `false`. This command can be executed only using api_key
543 543 belonging to user with admin rights
544 544
545 545
546 546 INPUT::
547 547
548 548 id : <id_for_response>
549 549 api_key : "<api_key>"
550 550 method : "add_user_users_group"
551 551 args: {
552 552 "usersgroupid" : "<users group id or name>",
553 553 "userid" : "<user_id or username>",
554 554 }
555 555
556 556 OUTPUT::
557 557
558 558 id : <id_given_in_input>
559 559 result: {
560 560 "success": True|False # depends on if member is in group
561 561 "msg": "added member `<username>` to users group `<groupname>` |
562 562 User is already in that group"
563 563 }
564 564 error: null
565 565
566 566
567 567 remove_user_from_users_group
568 568 ----------------------------
569 569
570 570 Removes a user from a users group. If user is not in given group success will
571 571 be `false`. This command can be executed only
572 572 using api_key belonging to user with admin rights
573 573
574 574
575 575 INPUT::
576 576
577 577 id : <id_for_response>
578 578 api_key : "<api_key>"
579 579 method : "remove_user_from_users_group"
580 580 args: {
581 581 "usersgroupid" : "<users group id or name>",
582 582 "userid" : "<user_id or username>",
583 583 }
584 584
585 585 OUTPUT::
586 586
587 587 id : <id_given_in_input>
588 588 result: {
589 589 "success": True|False, # depends on if member is in group
590 590 "msg": "removed member <username> from users group <groupname> |
591 591 User wasn't in group"
592 592 }
593 593 error: null
594 594
595 595
596 596 get_repo
597 597 --------
598 598
599 599 Gets an existing repository by it's name or repository_id. Members will return
600 600 either users_group or user associated to that repository. This command can be
601 601 executed only using api_key belonging to user with admin
602 602 rights or regular user that have at least read access to repository.
603 603
604 604
605 605 INPUT::
606 606
607 607 id : <id_for_response>
608 608 api_key : "<api_key>"
609 609 method : "get_repo"
610 610 args: {
611 611 "repoid" : "<reponame or repo_id>"
612 612 }
613 613
614 614 OUTPUT::
615 615
616 616 id : <id_given_in_input>
617 617 result: None if repository does not exist or
618 618 {
619 619 "repo_id" : "<repo_id>",
620 620 "repo_name" : "<reponame>"
621 621 "repo_type" : "<repo_type>",
622 622 "clone_uri" : "<clone_uri>",
623 623 "enable_downloads": "<bool>",
624 624 "enable_locking": "<bool>",
625 625 "enable_statistics": "<bool>",
626 626 "private": "<bool>",
627 627 "created_on" : "<date_time_created>",
628 628 "description" : "<description>",
629 629 "landing_rev": "<landing_rev>",
630 630 "last_changeset": {
631 631 "author": "<full_author>",
632 632 "date": "<date_time_of_commit>",
633 633 "message": "<commit_message>",
634 634 "raw_id": "<raw_id>",
635 635 "revision": "<numeric_revision>",
636 636 "short_id": "<short_id>"
637 637 }
638 638 "owner": "<repo_owner>",
639 639 "fork_of": "<name_of_fork_parent>",
640 640 "members" : [
641 641 {
642 642 "type": "user",
643 643 "user_id" : "<user_id>",
644 644 "username" : "<username>",
645 645 "firstname": "<firstname>",
646 646 "lastname" : "<lastname>",
647 647 "email" : "<email>",
648 648 "emails": "<list_of_all_additional_emails>",
649 649 "active" : "<bool>",
650 650 "admin" :Β  "<bool>",
651 651 "ldap_dn" : "<ldap_dn>",
652 652 "last_login": "<last_login>",
653 653 "permission" : "repository.(read|write|admin)"
654 654 },
655 655 …
656 656 {
657 657 "type": "users_group",
658 658 "id" : "<usersgroupid>",
659 659 "name" : "<usersgroupname>",
660 660 "active": "<bool>",
661 661 "permission" : "repository.(read|write|admin)"
662 662 },
663 663 …
664 664 ]
665 665 "followers": [
666 666 {
667 667 "user_id" : "<user_id>",
668 668 "username" : "<username>",
669 669 "firstname": "<firstname>",
670 670 "lastname" : "<lastname>",
671 671 "email" : "<email>",
672 672 "emails": "<list_of_all_additional_emails>",
673 673 "ip_addresses": "<list_of_ip_addresses_for_user>",
674 674 "active" : "<bool>",
675 675 "admin" :Β  "<bool>",
676 676 "ldap_dn" : "<ldap_dn>",
677 677 "last_login": "<last_login>",
678 678 },
679 679 …
680 680 ]
681 681 }
682 682 error: null
683 683
684 684
685 685 get_repos
686 686 ---------
687 687
688 688 Lists all existing repositories. This command can be executed only using
689 689 api_key belonging to user with admin rights or regular user that have
690 690 admin, write or read access to repository.
691 691
692 692
693 693 INPUT::
694 694
695 695 id : <id_for_response>
696 696 api_key : "<api_key>"
697 697 method : "get_repos"
698 698 args: { }
699 699
700 700 OUTPUT::
701 701
702 702 id : <id_given_in_input>
703 703 result: [
704 704 {
705 705 "repo_id" : "<repo_id>",
706 706 "repo_name" : "<reponame>"
707 707 "repo_type" : "<repo_type>",
708 708 "clone_uri" : "<clone_uri>",
709 709 "private": : "<bool>",
710 710 "created_on" : "<datetimecreated>",
711 711 "description" : "<description>",
712 712 "landing_rev": "<landing_rev>",
713 713 "owner": "<repo_owner>",
714 714 "fork_of": "<name_of_fork_parent>",
715 715 "enable_downloads": "<bool>",
716 716 "enable_locking": "<bool>",
717 717 "enable_statistics": "<bool>",
718 718 },
719 719 …
720 720 ]
721 721 error: null
722 722
723 723
724 724 get_repo_nodes
725 725 --------------
726 726
727 727 returns a list of nodes and it's children in a flat list for a given path
728 728 at given revision. It's possible to specify ret_type to show only `files` or
729 729 `dirs`. This command can be executed only using api_key belonging to user
730 730 with admin rights
731 731
732 732
733 733 INPUT::
734 734
735 735 id : <id_for_response>
736 736 api_key : "<api_key>"
737 737 method : "get_repo_nodes"
738 738 args: {
739 739 "repoid" : "<reponame or repo_id>"
740 740 "revision" : "<revision>",
741 741 "root_path" : "<root_path>",
742 742 "ret_type" : "<ret_type> = Optional('all')"
743 743 }
744 744
745 745 OUTPUT::
746 746
747 747 id : <id_given_in_input>
748 748 result: [
749 749 {
750 750 "name" : "<name>"
751 751 "type" : "<type>",
752 752 },
753 753 …
754 754 ]
755 755 error: null
756 756
757 757
758 758 create_repo
759 759 -----------
760 760
761 761 Creates a repository. If repository name contains "/", all needed repository
762 762 groups will be created. For example "foo/bar/baz" will create groups
763 763 "foo", "bar" (with "foo" as parent), and create "baz" repository with
764 764 "bar" as group. This command can be executed only using api_key belonging to user with admin
765 765 rights or regular user that have create repository permission. Regular users
766 766 cannot specify owner parameter
767 767
768 768
769 769 INPUT::
770 770
771 771 id : <id_for_response>
772 772 api_key : "<api_key>"
773 773 method : "create_repo"
774 774 args: {
775 775 "repo_name" : "<reponame>",
776 776 "owner" : "<onwer_name_or_id = Optional(=apiuser)>",
777 777 "repo_type" : "<repo_type> = Optional('hg')",
778 778 "description" : "<description> = Optional('')",
779 779 "private" : "<bool> = Optional(False)",
780 780 "clone_uri" : "<clone_uri> = Optional(None)",
781 781 "landing_rev" : "<landing_rev> = Optional('tip')",
782 782 "enable_downloads": "<bool> = Optional(False)",
783 783 "enable_locking": "<bool> = Optional(False)",
784 784 "enable_statistics": "<bool> = Optional(False)",
785 785 }
786 786
787 787 OUTPUT::
788 788
789 789 id : <id_given_in_input>
790 790 result: {
791 791 "msg": "Created new repository `<reponame>`",
792 792 "repo": {
793 793 "repo_id" : "<repo_id>",
794 794 "repo_name" : "<reponame>"
795 795 "repo_type" : "<repo_type>",
796 796 "clone_uri" : "<clone_uri>",
797 797 "private": : "<bool>",
798 798 "created_on" : "<datetimecreated>",
799 799 "description" : "<description>",
800 800 "landing_rev": "<landing_rev>",
801 801 "owner": "<username or user_id>",
802 802 "fork_of": "<name_of_fork_parent>",
803 803 "enable_downloads": "<bool>",
804 804 "enable_locking": "<bool>",
805 805 "enable_statistics": "<bool>",
806 806 },
807 807 }
808 808 error: null
809 809
810 810
811 811 fork_repo
812 812 ---------
813 813
814 814 Creates a fork of given repo. In case of using celery this will
815 815 immidiatelly return success message, while fork is going to be created
816 816 asynchronous. This command can be executed only using api_key belonging to
817 817 user with admin rights or regular user that have fork permission, and at least
818 818 read access to forking repository. Regular users cannot specify owner parameter.
819 819
820 820
821 821 INPUT::
822 822
823 823 id : <id_for_response>
824 824 api_key : "<api_key>"
825 825 method : "fork_repo"
826 826 args: {
827 827 "repoid" : "<reponame or repo_id>",
828 828 "fork_name": "<forkname>",
829 829 "owner": "<username or user_id = Optional(=apiuser)>",
830 830 "description": "<description>",
831 831 "copy_permissions": "<bool>",
832 832 "private": "<bool>",
833 833 "landing_rev": "<landing_rev>"
834 834
835 835 }
836 836
837 837 OUTPUT::
838 838
839 839 id : <id_given_in_input>
840 840 result: {
841 841 "msg": "Created fork of `<reponame>` as `<forkname>`",
842 842 "success": true
843 843 }
844 844 error: null
845 845
846 846
847 847 delete_repo
848 848 -----------
849 849
850 850 Deletes a repository. This command can be executed only using api_key belonging to user with admin
851 851 rights or regular user that have admin access to repository.
852 852
853 853
854 854 INPUT::
855 855
856 856 id : <id_for_response>
857 857 api_key : "<api_key>"
858 858 method : "delete_repo"
859 859 args: {
860 860 "repoid" : "<reponame or repo_id>"
861 861 }
862 862
863 863 OUTPUT::
864 864
865 865 id : <id_given_in_input>
866 866 result: {
867 867 "msg": "Deleted repository `<reponame>`",
868 868 "success": true
869 869 }
870 870 error: null
871 871
872 872
873 873 grant_user_permission
874 874 ---------------------
875 875
876 876 Grant permission for user on given repository, or update existing one
877 877 if found. This command can be executed only using api_key belonging to user
878 878 with admin rights.
879 879
880 880
881 881 INPUT::
882 882
883 883 id : <id_for_response>
884 884 api_key : "<api_key>"
885 885 method : "grant_user_permission"
886 886 args: {
887 887 "repoid" : "<reponame or repo_id>"
888 888 "userid" : "<username or user_id>"
889 889 "perm" : "(repository.(none|read|write|admin))",
890 890 }
891 891
892 892 OUTPUT::
893 893
894 894 id : <id_given_in_input>
895 895 result: {
896 896 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
897 897 "success": true
898 898 }
899 899 error: null
900 900
901 901
902 902 revoke_user_permission
903 903 ----------------------
904 904
905 905 Revoke permission for user on given repository. This command can be executed
906 906 only using api_key belonging to user with admin rights.
907 907
908 908
909 909 INPUT::
910 910
911 911 id : <id_for_response>
912 912 api_key : "<api_key>"
913 913 method : "revoke_user_permission"
914 914 args: {
915 915 "repoid" : "<reponame or repo_id>"
916 916 "userid" : "<username or user_id>"
917 917 }
918 918
919 919 OUTPUT::
920 920
921 921 id : <id_given_in_input>
922 922 result: {
923 923 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
924 924 "success": true
925 925 }
926 926 error: null
927 927
928 928
929 929 grant_users_group_permission
930 930 ----------------------------
931 931
932 932 Grant permission for users group on given repository, or update
933 933 existing one if found. This command can be executed only using
934 934 api_key belonging to user with admin rights.
935 935
936 936
937 937 INPUT::
938 938
939 939 id : <id_for_response>
940 940 api_key : "<api_key>"
941 941 method : "grant_users_group_permission"
942 942 args: {
943 943 "repoid" : "<reponame or repo_id>"
944 944 "usersgroupid" : "<users group id or name>"
945 945 "perm" : "(repository.(none|read|write|admin))",
946 946 }
947 947
948 948 OUTPUT::
949 949
950 950 id : <id_given_in_input>
951 951 result: {
952 952 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
953 953 "success": true
954 954 }
955 955 error: null
956 956
957 957
958 958 revoke_users_group_permission
959 959 -----------------------------
960 960
961 961 Revoke permission for users group on given repository.This command can be
962 962 executed only using api_key belonging to user with admin rights.
963 963
964 964 INPUT::
965 965
966 966 id : <id_for_response>
967 967 api_key : "<api_key>"
968 968 method : "revoke_users_group_permission"
969 969 args: {
970 970 "repoid" : "<reponame or repo_id>"
971 971 "usersgroupid" : "<users group id or name>"
972 972 }
973 973
974 974 OUTPUT::
975 975
976 976 id : <id_given_in_input>
977 977 result: {
978 978 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
979 979 "success": true
980 980 }
981 981 error: null
@@ -1,254 +1,254 b''
1 1 .. _installation_win:
2 2
3 3
4 4 Step by step Installation for Windows
5 5 =====================================
6 6
7 7
8 8 RhodeCode step-by-step install Guide for Windows
9 9
10 10 Target OS: Windows XP SP3 32bit English (Clean installation)
11 11 + All Windows Updates until 24-may-2012
12 12
13 13 .. note::
14 14
15 15 This installation is for 32bit systems, for 64bit windows you might need
16 16 to download proper 64bit version of "Windows Installer" and Win32py
17 17 extensions
18 18
19 19 Step1 - Install Visual Studio 2008 Express
20 20 ------------------------------------------
21 21
22 22
23 23 Optional: You can also install MingW, but VS2008 installation is easier
24 24
25 25 Download "Visual C++ 2008 Express Edition with SP1" from:
26 26 http://www.microsoft.com/visualstudio/en-us/products/2008-editions/express
27 27 (if not found or relocated, google for "visual studio 2008 express" for
28 28 updated link)
29 29
30 30 You can also download full ISO file for offline installation, just
31 31 choose "All - Offline Install ISO image file" in the previous page and
32 32 choose "Visual C++ 2008 Express" when installing.
33 33
34 34 .. note::
35
35
36 36 Using other versions of Visual Studio will lead to random crashes.
37 37 You must use Visual Studio 2008!"
38 38
39 39 .. note::
40 40
41 41 Silverlight Runtime and SQL Server 2008 Express Edition are not
42 42 required, you can uncheck them
43 43
44 44
45 45 Step2 - Install Python
46 46 ----------------------
47 47
48 48 Install Python 2.x.y (x >= 5) x86 version (32bit). DO NOT USE A 3.x version.
49 49 Download Python 2.x.y from:
50 50 http://www.python.org/download/
51 51
52 52 Choose "Windows Installer" (32bit version) not "Windows X86-64
53 53 Installer". While writing this guide, the latest version was v2.7.3.
54 54 Remember the specific major and minor version installed, because it will
55 55 be needed in the next step. In this case, it is "2.7".
56 56
57 57
58 58 Step3 - Install Win32py extensions
59 59 ----------------------------------
60 60
61 61 Download pywin32 from:
62 62 http://sourceforge.net/projects/pywin32/files/
63 63
64 64 - Click on "pywin32" folder
65 65 - Click on the first folder (in this case, Build 217, maybe newer when you try)
66 66 - Choose the file ending with ".win32-py2.x.exe" -> x being the minor
67 67 version of Python you installed (in this case, 7)
68 68 When writing this guide, the file was:
69 69 http://sourceforge.net/projects/pywin32/files/pywin32/Build%20217/pywin32-217.win32-py2.7.exe/download
70 70
71 71
72 72 Step4 - Python BIN
73 73 ------------------
74 74
75 75 Add Python BIN folder to the path
76 76
77 77 You have to add the Python folder to the path, you can do it manually
78 78 (editing "PATH" environment variable) or using Windows Support Tools
79 79 that came preinstalled in Vista/7 and can be installed in Windows XP.
80 80
81 81 - Using support tools on WINDOWS XP:
82 82 If you use Windows XP you can install them using Windows XP CD and
83 83 navigating to \SUPPORT\TOOLS. There, execute Setup.EXE (not MSI).
84 84 Afterwards, open a CMD and type::
85 85
86 86 SETX PATH "%PATH%;[your-python-path]" -M
87 87
88 88 Close CMD (the path variable will be updated then)
89 89
90 90 - Using support tools on WINDOWS Vista/7:
91 91
92 92 Open a CMD and type::
93 93
94 94 SETX PATH "%PATH%;[your-python-path]" /M
95 95
96 96 Please substitute [your-python-path] with your Python installation path.
97 97 Typically: C:\\Python27
98 98
99 99
100 100 Step5 - RhodeCode folder structure
101 101 ----------------------------------
102 102
103 103 Create a RhodeCode folder structure
104 104
105 105 This is only a example to install RhodeCode, you can of course change
106 106 it. However, this guide will follow the proposed structure, so please
107 107 later adapt the paths if you change them. My recommendation is to use
108 108 folders with NO SPACES. But you can try if you are brave...
109 109
110 110 Create the following folder structure::
111 111
112 112 C:\RhodeCode
113 113 C:\RhodeCode\Bin
114 114 C:\RhodeCode\Env
115 115 C:\RhodeCode\Repos
116 116
117 117
118 118 Step6 - Install virtualenv
119 119 ---------------------------
120 120
121 121 Install Virtual Env for Python
122 122
123 123 Navigate to: http://www.virtualenv.org/en/latest/index.html#installation
124 124 Right click on "virtualenv.py" file and choose "Save link as...".
125 125 Download to C:\\RhodeCode (or whatever you want)
126 126 (the file is located at
127 127 https://raw.github.com/pypa/virtualenv/master/virtualenv.py)
128 128
129 129 Create a virtual Python environment in C:\\RhodeCode\\Env (or similar). To
130 130 do so, open a CMD (Python Path should be included in Step3), navigate
131 131 where you downloaded "virtualenv.py", and write::
132 132
133 133 python virtualenv.py C:\RhodeCode\Env
134 134
135 135 (--no-site-packages is now the default behaviour of virtualenv, no need
136 136 to include it)
137 137
138 138
139 139 Step7 - Install RhodeCode
140 140 -------------------------
141 141
142 142 Finally, install RhodeCode
143 143
144 144 Close previously opened command prompt/s, and open a Visual Studio 2008
145 145 Command Prompt (**IMPORTANT!!**). To do so, go to Start Menu, and then open
146 146 "Microsoft Visual C++ 2008 Express Edition" -> "Visual Studio Tools" ->
147 147 "Visual Studio 2008 Command Prompt"
148 148
149 149 In that CMD (loaded with VS2008 PATHs) type::
150 150
151 151 cd C:\RhodeCode\Env\Scripts (or similar)
152 152 activate
153 153
154 154 The prompt will change into "(Env) C:\\RhodeCode\\Env\\Scripts" or similar
155 155 (depending of your folder structure). Then type::
156 156
157 157 pip install rhodecode
158 158
159 159 (long step, please wait until fully complete)
160 160
161 161 Some warnings will appear, don't worry as they are normal.
162 162
163 163
164 164 Step8 - Configuring RhodeCode
165 165 -----------------------------
166 166
167 167
168 168 steps taken from http://packages.python.org/RhodeCode/setup.html
169 169
170 170 You have to use the same Visual Studio 2008 command prompt as Step7, so
171 171 if you closed it reopen it following the same commands (including the
172 172 "activate" one). When ready, just type::
173 173
174 174 cd C:\RhodeCode\Bin
175 175 paster make-config RhodeCode production.ini
176 176
177 177 Then, you must edit production.ini to fit your needs (ip address, ip
178 178 port, mail settings, database, whatever). I recommend using NotePad++
179 179 (free) or similar text editor, as it handles well the EndOfLine
180 180 character differences between Unix and Windows
181 181 (http://notepad-plus-plus.org/)
182 182
183 183 For the sake of simplicity lets run it with the default settings. After
184 184 your edits (if any), in the previous Command Prompt, type::
185 185
186 186 paster setup-rhodecode production.ini
187 187
188 188 (this time a NEW database will be installed, you must follow a different
189 189 step to later UPGRADE to a newer RhodeCode version)
190 190
191 191 The script will ask you for confirmation about creating a NEW database,
192 192 answer yes (y)
193 193 The script will ask you for repository path, answer C:\\RhodeCode\\Repos
194 194 (or similar)
195 195 The script will ask you for admin username and password, answer "admin"
196 196 + "123456" (or whatever you want)
197 197 The script will ask you for admin mail, answer "admin@xxxx.com" (or
198 198 whatever you want)
199 199
200 200 If you make some mistake and the script does not end, don't worry, start
201 201 it again.
202 202
203 203
204 204 Step9 - Running RhodeCode
205 205 -------------------------
206 206
207 207
208 208 In the previous command prompt, being in the C:\\RhodeCode\\Bin folder,
209 209 just type::
210 210
211 211 paster serve production.ini
212 212
213 213 Open yout web server, and go to http://127.0.0.1:5000
214 214
215 215 It works!! :-)
216 216
217 217 Remark:
218 218 If it does not work first time, just Ctrl-C the CMD process and start it
219 219 again. Don't forget the "http://" in Internet Explorer
220 220
221 221
222 222
223 223 What this Guide does not cover:
224 224
225 225 - Installing Celery
226 226 - Running RhodeCode as Windows Service. You can investigate here:
227 227
228 228 - http://pypi.python.org/pypi/wsgisvc
229 229 - http://ryrobes.com/python/running-python-scripts-as-a-windows-service/
230 230 - http://wiki.pylonshq.com/display/pylonscookbook/How+to+run+Pylons+as+a+Windows+service
231 231
232 232 - Using Apache. You can investigate here:
233 233
234 234 - https://groups.google.com/group/rhodecode/msg/c433074e813ffdc4
235 235
236 236
237 237 Upgrading
238 238 =========
239 239
240 240 Stop running RhodeCode
241 241 Open a CommandPrompt like in Step7 (VS2008 path + activate) and type::
242 242
243 243 easy_install -U rhodecode
244 244 cd \RhodeCode\Bin
245 245
246 246 { backup your production.ini file now} ::
247 247
248 248 paster make-config RhodeCode production.ini
249 249
250 250 (check changes and update your production.ini accordingly) ::
251 251
252 252 paster upgrade-db production.ini (update database)
253 253
254 254 Full steps in http://packages.python.org/RhodeCode/upgrade.html
@@ -1,735 +1,735 b''
1 1 .. _setup:
2 2
3 3 =====
4 4 Setup
5 5 =====
6 6
7 7
8 8 Setting up RhodeCode
9 9 --------------------
10 10
11 11 First, you will need to create a RhodeCode configuration file. Run the
12 12 following command to do this::
13 13
14 14 paster make-config RhodeCode production.ini
15 15
16 16 - This will create the file `production.ini` in the current directory. This
17 17 configuration file contains the various settings for RhodeCode, e.g proxy
18 18 port, email settings, usage of static files, cache, celery settings and
19 19 logging.
20 20
21 21
22 22 Next, you need to create the databases used by RhodeCode. I recommend that you
23 23 use postgresql or sqlite (default). If you choose a database other than the
24 24 default ensure you properly adjust the db url in your production.ini
25 25 configuration file to use this other database. RhodeCode currently supports
26 26 postgresql, sqlite and mysql databases. Create the database by running
27 27 the following command::
28 28
29 29 paster setup-rhodecode production.ini
30 30
31 31 This will prompt you for a "root" path. This "root" path is the location where
32 32 RhodeCode will store all of its repositories on the current machine. After
33 33 entering this "root" path ``setup-rhodecode`` will also prompt you for a username
34 34 and password for the initial admin account which ``setup-rhodecode`` sets
35 35 up for you.
36 36
37 37 setup process can be fully automated, example for lazy::
38 38
39 39 paster setup-rhodecode production.ini --user=marcink --password=secret --email=marcin@rhodecode.org --repos=/home/marcink/my_repos
40 40
41 41
42 42 - The ``setup-rhodecode`` command will create all of the needed tables and an
43 43 admin account. When choosing a root path you can either use a new empty
44 44 location, or a location which already contains existing repositories. If you
45 45 choose a location which contains existing repositories RhodeCode will simply
46 46 add all of the repositories at the chosen location to it's database.
47 47 (Note: make sure you specify the correct path to the root).
48 48 - Note: the given path for mercurial_ repositories **must** be write accessible
49 49 for the application. It's very important since the RhodeCode web interface
50 50 will work without write access, but when trying to do a push it will
51 51 eventually fail with permission denied errors unless it has write access.
52 52
53 53 You are now ready to use RhodeCode, to run it simply execute::
54 54
55 55 paster serve production.ini
56 56
57 57 - This command runs the RhodeCode server. The web app should be available at the
58 58 127.0.0.1:5000. This ip and port is configurable via the production.ini
59 59 file created in previous step
60 60 - Use the admin account you created above when running ``setup-rhodecode``
61 61 to login to the web app.
62 62 - The default permissions on each repository is read, and the owner is admin.
63 63 Remember to update these if needed.
64 64 - In the admin panel you can toggle ldap, anonymous, permissions settings. As
65 65 well as edit more advanced options on users and repositories
66 66
67 67 Optionally users can create `rcextensions` package that extends RhodeCode
68 68 functionality. To do this simply execute::
69 69
70 70 paster make-rcext production.ini
71 71
72 72 This will create `rcextensions` package in the same place that your `ini` file
73 73 lives. With `rcextensions` it's possible to add additional mapping for whoosh,
74 74 stats and add additional code into the push/pull/create/delete repo hooks.
75 75 For example for sending signals to build-bots such as jenkins.
76 76 Please see the `__init__.py` file inside `rcextensions` package
77 77 for more details.
78 78
79 79
80 80 Using RhodeCode with SSH
81 81 ------------------------
82 82
83 83 RhodeCode currently only hosts repositories using http and https. (The addition
84 84 of ssh hosting is a planned future feature.) However you can easily use ssh in
85 85 parallel with RhodeCode. (Repository access via ssh is a standard "out of
86 86 the box" feature of mercurial_ and you can use this to access any of the
87 87 repositories that RhodeCode is hosting. See PublishingRepositories_)
88 88
89 89 RhodeCode repository structures are kept in directories with the same name
90 90 as the project. When using repository groups, each group is a subdirectory.
91 91 This allows you to easily use ssh for accessing repositories.
92 92
93 93 In order to use ssh you need to make sure that your web-server and the users
94 94 login accounts have the correct permissions set on the appropriate directories.
95 95 (Note that these permissions are independent of any permissions you have set up
96 96 using the RhodeCode web interface.)
97 97
98 98 If your main directory (the same as set in RhodeCode settings) is for example
99 99 set to **/home/hg** and the repository you are using is named `rhodecode`, then
100 100 to clone via ssh you should run::
101 101
102 102 hg clone ssh://user@server.com/home/hg/rhodecode
103 103
104 104 Using other external tools such as mercurial-server_ or using ssh key based
105 105 authentication is fully supported.
106 106
107 107 Note: In an advanced setup, in order for your ssh access to use the same
108 108 permissions as set up via the RhodeCode web interface, you can create an
109 109 authentication hook to connect to the rhodecode db and runs check functions for
110 110 permissions against that.
111 111
112 112 Setting up Whoosh full text search
113 113 ----------------------------------
114 114
115 115 Starting from version 1.1 the whoosh index can be build by using the paster
116 116 command ``make-index``. To use ``make-index`` you must specify the configuration
117 117 file that stores the location of the index. You may specify the location of the
118 118 repositories (`--repo-location`). If not specified, this value is retrieved
119 119 from the RhodeCode database. This was required prior to 1.2. Starting from
120 120 version 1.2 it is also possible to specify a comma separated list of
121 121 repositories (`--index-only`) to build index only on chooses repositories
122 122 skipping any other found in repos location
123 123
124 124 You may optionally pass the option `-f` to enable a full index rebuild. Without
125 125 the `-f` option, indexing will run always in "incremental" mode.
126 126
127 127 For an incremental index build use::
128 128
129 paster make-index production.ini
129 paster make-index production.ini
130 130
131 131 For a full index rebuild use::
132 132
133 paster make-index production.ini -f
133 paster make-index production.ini -f
134 134
135 135
136 136 building index just for chosen repositories is possible with such command::
137 137
138 138 paster make-index production.ini --index-only=vcs,rhodecode
139 139
140 140
141 141 In order to do periodical index builds and keep your index always up to date.
142 142 It's recommended to do a crontab entry for incremental indexing.
143 143 An example entry might look like this::
144 144
145 145 /path/to/python/bin/paster make-index /path/to/rhodecode/production.ini
146 146
147 147 When using incremental mode (the default) whoosh will check the last
148 148 modification date of each file and add it to be reindexed if a newer file is
149 149 available. The indexing daemon checks for any removed files and removes them
150 150 from index.
151 151
152 152 If you want to rebuild index from scratch, you can use the `-f` flag as above,
153 153 or in the admin panel you can check `build from scratch` flag.
154 154
155 155
156 156 Setting up LDAP support
157 157 -----------------------
158 158
159 159 RhodeCode starting from version 1.1 supports ldap authentication. In order
160 160 to use LDAP, you have to install the python-ldap_ package. This package is
161 161 available via pypi, so you can install it by running
162 162
163 163 using easy_install::
164 164
165 165 easy_install python-ldap
166 166
167 167 using pip::
168 168
169 169 pip install python-ldap
170 170
171 171 .. note::
172 172 python-ldap requires some certain libs on your system, so before installing
173 173 it check that you have at least `openldap`, and `sasl` libraries.
174 174
175 175 LDAP settings are located in admin->ldap section,
176 176
177 177 Here's a typical ldap setup::
178 178
179 179 Connection settings
180 180 Enable LDAP = checked
181 181 Host = host.example.org
182 182 Port = 389
183 183 Account = <account>
184 184 Password = <password>
185 185 Connection Security = LDAPS connection
186 186 Certificate Checks = DEMAND
187 187
188 188 Search settings
189 189 Base DN = CN=users,DC=host,DC=example,DC=org
190 190 LDAP Filter = (&(objectClass=user)(!(objectClass=computer)))
191 191 LDAP Search Scope = SUBTREE
192 192
193 193 Attribute mappings
194 194 Login Attribute = uid
195 195 First Name Attribute = firstName
196 196 Last Name Attribute = lastName
197 197 E-mail Attribute = mail
198 198
199 199 .. _enable_ldap:
200 200
201 201 Enable LDAP : required
202 202 Whether to use LDAP for authenticating users.
203 203
204 204 .. _ldap_host:
205 205
206 206 Host : required
207 207 LDAP server hostname or IP address. Can be also a comma separated
208 208 list of servers to support LDAP fail-over.
209 209
210 210 .. _Port:
211 211
212 212 Port : required
213 213 389 for un-encrypted LDAP, 636 for SSL-encrypted LDAP.
214 214
215 215 .. _ldap_account:
216 216
217 217 Account : optional
218 218 Only required if the LDAP server does not allow anonymous browsing of
219 219 records. This should be a special account for record browsing. This
220 220 will require `LDAP Password`_ below.
221 221
222 222 .. _LDAP Password:
223 223
224 224 Password : optional
225 225 Only required if the LDAP server does not allow anonymous browsing of
226 226 records.
227 227
228 228 .. _Enable LDAPS:
229 229
230 230 Connection Security : required
231 231 Defines the connection to LDAP server
232 232
233 233 No encryption
234 234 Plain non encrypted connection
235 235
236 236 LDAPS connection
237 237 Enable ldaps connection. It will likely require `Port`_ to be set to
238 238 a different value (standard LDAPS port is 636). When LDAPS is enabled
239 239 then `Certificate Checks`_ is required.
240 240
241 241 START_TLS on LDAP connection
242 242 START TLS connection
243 243
244 244 .. _Certificate Checks:
245 245
246 246 Certificate Checks : optional
247 247 How SSL certificates verification is handled - this is only useful when
248 248 `Enable LDAPS`_ is enabled. Only DEMAND or HARD offer full SSL security
249 249 while the other options are susceptible to man-in-the-middle attacks. SSL
250 250 certificates can be installed to /etc/openldap/cacerts so that the
251 251 DEMAND or HARD options can be used with self-signed certificates or
252 252 certificates that do not have traceable certificates of authority.
253 253
254 254 NEVER
255 255 A serve certificate will never be requested or checked.
256 256
257 257 ALLOW
258 258 A server certificate is requested. Failure to provide a
259 259 certificate or providing a bad certificate will not terminate the
260 260 session.
261 261
262 262 TRY
263 263 A server certificate is requested. Failure to provide a
264 264 certificate does not halt the session; providing a bad certificate
265 265 halts the session.
266 266
267 267 DEMAND
268 268 A server certificate is requested and must be provided and
269 269 authenticated for the session to proceed.
270 270
271 271 HARD
272 272 The same as DEMAND.
273 273
274 274 .. _Base DN:
275 275
276 276 Base DN : required
277 277 The Distinguished Name (DN) where searches for users will be performed.
278 278 Searches can be controlled by `LDAP Filter`_ and `LDAP Search Scope`_.
279 279
280 280 .. _LDAP Filter:
281 281
282 282 LDAP Filter : optional
283 283 A LDAP filter defined by RFC 2254. This is more useful when `LDAP
284 284 Search Scope`_ is set to SUBTREE. The filter is useful for limiting
285 285 which LDAP objects are identified as representing Users for
286 286 authentication. The filter is augmented by `Login Attribute`_ below.
287 287 This can commonly be left blank.
288 288
289 289 .. _LDAP Search Scope:
290 290
291 291 LDAP Search Scope : required
292 292 This limits how far LDAP will search for a matching object.
293 293
294 294 BASE
295 295 Only allows searching of `Base DN`_ and is usually not what you
296 296 want.
297 297
298 298 ONELEVEL
299 299 Searches all entries under `Base DN`_, but not Base DN itself.
300 300
301 301 SUBTREE
302 302 Searches all entries below `Base DN`_, but not Base DN itself.
303 303 When using SUBTREE `LDAP Filter`_ is useful to limit object
304 304 location.
305 305
306 306 .. _Login Attribute:
307 307
308 308 Login Attribute : required
309 309 The LDAP record attribute that will be matched as the USERNAME or
310 310 ACCOUNT used to connect to RhodeCode. This will be added to `LDAP
311 311 Filter`_ for locating the User object. If `LDAP Filter`_ is specified as
312 312 "LDAPFILTER", `Login Attribute`_ is specified as "uid" and the user has
313 313 connected as "jsmith" then the `LDAP Filter`_ will be augmented as below
314 314 ::
315 315
316 316 (&(LDAPFILTER)(uid=jsmith))
317 317
318 318 .. _ldap_attr_firstname:
319 319
320 320 First Name Attribute : required
321 321 The LDAP record attribute which represents the user's first name.
322 322
323 323 .. _ldap_attr_lastname:
324 324
325 325 Last Name Attribute : required
326 326 The LDAP record attribute which represents the user's last name.
327 327
328 328 .. _ldap_attr_email:
329 329
330 330 Email Attribute : required
331 331 The LDAP record attribute which represents the user's email address.
332 332
333 333 If all data are entered correctly, and python-ldap_ is properly installed
334 334 users should be granted access to RhodeCode with ldap accounts. At this
335 335 time user information is copied from LDAP into the RhodeCode user database.
336 336 This means that updates of an LDAP user object may not be reflected as a
337 337 user update in RhodeCode.
338 338
339 339 If You have problems with LDAP access and believe You entered correct
340 340 information check out the RhodeCode logs, any error messages sent from LDAP
341 341 will be saved there.
342 342
343 343 Active Directory
344 344 ''''''''''''''''
345 345
346 346 RhodeCode can use Microsoft Active Directory for user authentication. This
347 347 is done through an LDAP or LDAPS connection to Active Directory. The
348 348 following LDAP configuration settings are typical for using Active
349 349 Directory ::
350 350
351 351 Base DN = OU=SBSUsers,OU=Users,OU=MyBusiness,DC=v3sys,DC=local
352 352 Login Attribute = sAMAccountName
353 353 First Name Attribute = givenName
354 354 Last Name Attribute = sn
355 355 E-mail Attribute = mail
356 356
357 357 All other LDAP settings will likely be site-specific and should be
358 358 appropriately configured.
359 359
360 360
361 361 Authentication by container or reverse-proxy
362 362 --------------------------------------------
363 363
364 364 Starting with version 1.3, RhodeCode supports delegating the authentication
365 365 of users to its WSGI container, or to a reverse-proxy server through which all
366 366 clients access the application.
367 367
368 368 When these authentication methods are enabled in RhodeCode, it uses the
369 369 username that the container/proxy (Apache/Nginx/etc) authenticated and doesn't
370 370 perform the authentication itself. The authorization, however, is still done by
371 371 RhodeCode according to its settings.
372 372
373 373 When a user logs in for the first time using these authentication methods,
374 374 a matching user account is created in RhodeCode with default permissions. An
375 375 administrator can then modify it using RhodeCode's admin interface.
376 376 It's also possible for an administrator to create accounts and configure their
377 377 permissions before the user logs in for the first time.
378 378
379 379 Container-based authentication
380 380 ''''''''''''''''''''''''''''''
381 381
382 382 In a container-based authentication setup, RhodeCode reads the user name from
383 383 the ``REMOTE_USER`` server variable provided by the WSGI container.
384 384
385 385 After setting up your container (see `Apache's WSGI config`_), you'd need
386 386 to configure it to require authentication on the location configured for
387 387 RhodeCode.
388 388
389 389 In order for RhodeCode to start using the provided username, you should set the
390 390 following in the [app:main] section of your .ini file::
391 391
392 392 container_auth_enabled = true
393 393
394 394
395 395 Proxy pass-through authentication
396 396 '''''''''''''''''''''''''''''''''
397 397
398 398 In a proxy pass-through authentication setup, RhodeCode reads the user name
399 399 from the ``X-Forwarded-User`` request header, which should be configured to be
400 400 sent by the reverse-proxy server.
401 401
402 402 After setting up your proxy solution (see `Apache virtual host reverse proxy example`_,
403 403 `Apache as subdirectory`_ or `Nginx virtual host example`_), you'd need to
404 404 configure the authentication and add the username in a request header named
405 405 ``X-Forwarded-User``.
406 406
407 407 For example, the following config section for Apache sets a subdirectory in a
408 408 reverse-proxy setup with basic auth::
409 409
410 410 <Location /<someprefix> >
411 411 ProxyPass http://127.0.0.1:5000/<someprefix>
412 412 ProxyPassReverse http://127.0.0.1:5000/<someprefix>
413 413 SetEnvIf X-Url-Scheme https HTTPS=1
414 414
415 415 AuthType Basic
416 416 AuthName "RhodeCode authentication"
417 417 AuthUserFile /home/web/rhodecode/.htpasswd
418 418 require valid-user
419 419
420 420 RequestHeader unset X-Forwarded-User
421 421
422 422 RewriteEngine On
423 423 RewriteCond %{LA-U:REMOTE_USER} (.+)
424 424 RewriteRule .* - [E=RU:%1]
425 425 RequestHeader set X-Forwarded-User %{RU}e
426 426 </Location>
427 427
428 428 In order for RhodeCode to start using the forwarded username, you should set
429 429 the following in the [app:main] section of your .ini file::
430 430
431 431 proxypass_auth_enabled = true
432 432
433 433 .. note::
434 434 If you enable proxy pass-through authentication, make sure your server is
435 435 only accessible through the proxy. Otherwise, any client would be able to
436 436 forge the authentication header and could effectively become authenticated
437 437 using any account of their liking.
438 438
439 439 Integration with Issue trackers
440 440 -------------------------------
441 441
442 442 RhodeCode provides a simple integration with issue trackers. It's possible
443 443 to define a regular expression that will fetch issue id stored in commit
444 444 messages and replace that with an url to this issue. To enable this simply
445 445 uncomment following variables in the ini file::
446 446
447 447 url_pat = (?:^#|\s#)(\w+)
448 448 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
449 449 issue_prefix = #
450 450
451 451 `url_pat` is the regular expression that will fetch issues from commit messages.
452 452 Default regex will match issues in format of #<number> eg. #300.
453 453
454 454 Matched issues will be replace with the link specified as `issue_server_link`
455 455 {id} will be replaced with issue id, and {repo} with repository name.
456 456 Since the # is striped `issue_prefix` is added as a prefix to url.
457 457 `issue_prefix` can be something different than # if you pass
458 458 ISSUE- as issue prefix this will generate an url in format::
459 459
460 460 <a href="https://myissueserver.com/example_repo/issue/300">ISSUE-300</a>
461 461
462 462 Hook management
463 463 ---------------
464 464
465 465 Hooks can be managed in similar way to this used in .hgrc files.
466 466 To access hooks setting click `advanced setup` on Hooks section of Mercurial
467 467 Settings in Admin.
468 468
469 469 There are 4 built in hooks that cannot be changed (only enable/disable by
470 470 checkboxes on previos section).
471 471 To add another custom hook simply fill in first section with
472 472 <name>.<hook_type> and the second one with hook path. Example hooks
473 473 can be found at *rhodecode.lib.hooks*.
474 474
475 475
476 476 Changing default encoding
477 477 -------------------------
478 478
479 479 By default RhodeCode uses utf8 encoding, starting from 1.3 series this
480 480 can be changed, simply edit default_encoding in .ini file to desired one.
481 481 This affects many parts in rhodecode including commiters names, filenames,
482 482 encoding of commit messages. In addition RhodeCode can detect if `chardet`
483 483 library is installed. If `chardet` is detected RhodeCode will fallback to it
484 484 when there are encode/decode errors.
485 485
486 486
487 487 Setting Up Celery
488 488 -----------------
489 489
490 490 Since version 1.1 celery is configured by the rhodecode ini configuration files.
491 491 Simply set use_celery=true in the ini file then add / change the configuration
492 492 variables inside the ini file.
493 493
494 494 Remember that the ini files use the format with '.' not with '_' like celery.
495 495 So for example setting `BROKER_HOST` in celery means setting `broker.host` in
496 496 the config file.
497 497
498 498 In order to start using celery run::
499 499
500 500 paster celeryd <configfile.ini>
501 501
502 502
503 503 .. note::
504 504 Make sure you run this command from the same virtualenv, and with the same
505 505 user that rhodecode runs.
506 506
507 507 HTTPS support
508 508 -------------
509 509
510 510 There are two ways to enable https:
511 511
512 512 - Set HTTP_X_URL_SCHEME in your http server headers, than rhodecode will
513 513 recognize this headers and make proper https redirections
514 514 - Alternatively, change the `force_https = true` flag in the ini configuration
515 515 to force using https, no headers are needed than to enable https
516 516
517 517
518 518 Nginx virtual host example
519 519 --------------------------
520 520
521 521 Sample config for nginx using proxy::
522 522
523 523 upstream rc {
524 524 server 127.0.0.1:5000;
525 525 # add more instances for load balancing
526 526 #server 127.0.0.1:5001;
527 527 #server 127.0.0.1:5002;
528 528 }
529 529
530 530 server {
531 531 listen 443;
532 532 server_name rhodecode.myserver.com;
533 533 access_log /var/log/nginx/rhodecode.access.log;
534 534 error_log /var/log/nginx/rhodecode.error.log;
535 535
536 536 ssl on;
537 537 ssl_certificate rhodecode.myserver.com.crt;
538 538 ssl_certificate_key rhodecode.myserver.com.key;
539 539
540 540 ssl_session_timeout 5m;
541 541
542 542 ssl_protocols SSLv3 TLSv1;
543 543 ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
544 544 ssl_prefer_server_ciphers on;
545 545
546 546 # uncomment if you have nginx with chunking module compiled
547 547 # fixes the issues of having to put postBuffer data for large git
548 548 # pushes
549 549 #chunkin on;
550 550 #error_page 411 = @my_411_error;
551 551 #location @my_411_error {
552 552 # chunkin_resume;
553 553 #}
554 554
555 555 # uncomment if you want to serve static files by nginx
556 556 #root /path/to/installation/rhodecode/public;
557 557
558 558 location / {
559 559 try_files $uri @rhode;
560 560 }
561 561
562 562 location @rhode {
563 563 proxy_pass http://rc;
564 564 include /etc/nginx/proxy.conf;
565 565 }
566 566
567 567 }
568 568
569 569 Here's the proxy.conf. It's tuned so it will not timeout on long
570 570 pushes or large pushes::
571 571
572 572 proxy_redirect off;
573 573 proxy_set_header Host $host;
574 574 proxy_set_header X-Url-Scheme $scheme;
575 575 proxy_set_header X-Host $http_host;
576 576 proxy_set_header X-Real-IP $remote_addr;
577 577 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
578 578 proxy_set_header Proxy-host $proxy_host;
579 579 client_max_body_size 400m;
580 580 client_body_buffer_size 128k;
581 581 proxy_buffering off;
582 582 proxy_connect_timeout 7200;
583 583 proxy_send_timeout 7200;
584 584 proxy_read_timeout 7200;
585 585 proxy_buffers 8 32k;
586 586
587 587 Also, when using root path with nginx you might set the static files to false
588 588 in the production.ini file::
589 589
590 590 [app:main]
591 591 use = egg:rhodecode
592 592 full_stack = true
593 593 static_files = false
594 594 lang=en
595 595 cache_dir = %(here)s/data
596 596
597 597 In order to not have the statics served by the application. This improves speed.
598 598
599 599
600 600 Apache virtual host reverse proxy example
601 601 -----------------------------------------
602 602
603 603 Here is a sample configuration file for apache using proxy::
604 604
605 605 <VirtualHost *:80>
606 606 ServerName hg.myserver.com
607 607 ServerAlias hg.myserver.com
608 608
609 609 <Proxy *>
610 610 Order allow,deny
611 611 Allow from all
612 612 </Proxy>
613 613
614 614 #important !
615 615 #Directive to properly generate url (clone url) for pylons
616 616 ProxyPreserveHost On
617 617
618 618 #rhodecode instance
619 619 ProxyPass / http://127.0.0.1:5000/
620 620 ProxyPassReverse / http://127.0.0.1:5000/
621 621
622 622 #to enable https use line below
623 623 #SetEnvIf X-Url-Scheme https HTTPS=1
624 624
625 625 </VirtualHost>
626 626
627 627
628 628 Additional tutorial
629 629 http://wiki.pylonshq.com/display/pylonscookbook/Apache+as+a+reverse+proxy+for+Pylons
630 630
631 631
632 632 Apache as subdirectory
633 633 ----------------------
634 634
635 635 Apache subdirectory part::
636 636
637 637 <Location /<someprefix> >
638 638 ProxyPass http://127.0.0.1:5000/<someprefix>
639 639 ProxyPassReverse http://127.0.0.1:5000/<someprefix>
640 640 SetEnvIf X-Url-Scheme https HTTPS=1
641 641 </Location>
642 642
643 643 Besides the regular apache setup you will need to add the following line
644 644 into [app:main] section of your .ini file::
645 645
646 646 filter-with = proxy-prefix
647 647
648 648 Add the following at the end of the .ini file::
649 649
650 650 [filter:proxy-prefix]
651 651 use = egg:PasteDeploy#prefix
652 652 prefix = /<someprefix>
653 653
654 654
655 655 then change <someprefix> into your choosen prefix
656 656
657 657 Apache's WSGI config
658 658 --------------------
659 659
660 660 Alternatively, RhodeCode can be set up with Apache under mod_wsgi. For
661 661 that, you'll need to:
662 662
663 663 - Install mod_wsgi. If using a Debian-based distro, you can install
664 664 the package libapache2-mod-wsgi::
665 665
666 666 aptitude install libapache2-mod-wsgi
667 667
668 668 - Enable mod_wsgi::
669 669
670 670 a2enmod wsgi
671 671
672 672 - Create a wsgi dispatch script, like the one below. Make sure you
673 673 check the paths correctly point to where you installed RhodeCode
674 674 and its Python Virtual Environment.
675 675 - Enable the WSGIScriptAlias directive for the wsgi dispatch script,
676 676 as in the following example. Once again, check the paths are
677 677 correctly specified.
678 678
679 679 Here is a sample excerpt from an Apache Virtual Host configuration file::
680 680
681 681 WSGIDaemonProcess pylons \
682 682 threads=4 \
683 683 python-path=/home/web/rhodecode/pyenv/lib/python2.6/site-packages
684 684 WSGIScriptAlias / /home/web/rhodecode/dispatch.wsgi
685 685 WSGIPassAuthorization On
686 686
687 687 .. note::
688 688 when running apache as root please add: `user=www-data group=www-data`
689 689 into above configuration
690 690
691 691 .. note::
692 692 RhodeCode cannot be runned in multiprocess mode in apache, make sure
693 693 you don't specify `processes=num` directive in the config
694 694
695 695
696 696 Example wsgi dispatch script::
697 697
698 698 import os
699 699 os.environ["HGENCODING"] = "UTF-8"
700 700 os.environ['PYTHON_EGG_CACHE'] = '/home/web/rhodecode/.egg-cache'
701 701
702 702 # sometimes it's needed to set the curent dir
703 703 os.chdir('/home/web/rhodecode/')
704 704
705 705 import site
706 706 site.addsitedir("/home/web/rhodecode/pyenv/lib/python2.6/site-packages")
707 707
708 708 from paste.deploy import loadapp
709 709 from paste.script.util.logging_config import fileConfig
710 710
711 711 fileConfig('/home/web/rhodecode/production.ini')
712 712 application = loadapp('config:/home/web/rhodecode/production.ini')
713 713
714 714 Note: when using mod_wsgi you'll need to install the same version of
715 715 Mercurial that's inside RhodeCode's virtualenv also on the system's Python
716 716 environment.
717 717
718 718
719 719 Other configuration files
720 720 -------------------------
721 721
722 722 Some example init.d scripts can be found in init.d directory::
723 723
724 724 https://secure.rhodecode.org/rhodecode/files/beta/init.d
725 725
726 726 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
727 727 .. _python: http://www.python.org/
728 728 .. _mercurial: http://mercurial.selenic.com/
729 729 .. _celery: http://celeryproject.org/
730 730 .. _rabbitmq: http://www.rabbitmq.com/
731 731 .. _python-ldap: http://www.python-ldap.org/
732 732 .. _mercurial-server: http://www.lshift.net/mercurial-server.html
733 733 .. _PublishingRepositories: http://mercurial.selenic.com/wiki/PublishingRepositories
734 734 .. _Issues tracker: https://bitbucket.org/marcinkuzminski/rhodecode/issues
735 735 .. _google group rhodecode: http://groups.google.com/group/rhodecode
@@ -1,606 +1,606 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.files
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Files controller for RhodeCode
7 7
8 8 :created_on: Apr 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 from __future__ import with_statement
26 26 import os
27 27 import logging
28 28 import traceback
29 29 import tempfile
30 30
31 31 from pylons import request, response, tmpl_context as c, url
32 32 from pylons.i18n.translation import _
33 33 from pylons.controllers.util import redirect
34 34 from rhodecode.lib.utils import jsonify
35 35
36 36 from rhodecode.lib import diffs
37 37 from rhodecode.lib import helpers as h
38 38
39 39 from rhodecode.lib.compat import OrderedDict
40 40 from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str,\
41 41 str2bool
42 42 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
43 43 from rhodecode.lib.base import BaseRepoController, render
44 44 from rhodecode.lib.vcs.backends.base import EmptyChangeset
45 45 from rhodecode.lib.vcs.conf import settings
46 46 from rhodecode.lib.vcs.exceptions import RepositoryError, \
47 47 ChangesetDoesNotExistError, EmptyRepositoryError, \
48 48 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError,\
49 49 NodeDoesNotExistError, ChangesetError, NodeError
50 50 from rhodecode.lib.vcs.nodes import FileNode
51 51
52 52 from rhodecode.model.repo import RepoModel
53 53 from rhodecode.model.scm import ScmModel
54 54 from rhodecode.model.db import Repository
55 55
56 56 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
57 57 _context_url, get_line_ctx, get_ignore_ws
58 58
59 59
60 60 log = logging.getLogger(__name__)
61 61
62 62
63 63 class FilesController(BaseRepoController):
64 64
65 65 def __before__(self):
66 66 super(FilesController, self).__before__()
67 67 c.cut_off_limit = self.cut_off_limit
68 68
69 69 def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
70 70 """
71 71 Safe way to get changeset if error occur it redirects to tip with
72 72 proper message
73 73
74 74 :param rev: revision to fetch
75 75 :param repo_name: repo name to redirect after
76 76 """
77 77
78 78 try:
79 79 return c.rhodecode_repo.get_changeset(rev)
80 80 except EmptyRepositoryError, e:
81 81 if not redirect_after:
82 82 return None
83 83 url_ = url('files_add_home',
84 84 repo_name=c.repo_name,
85 85 revision=0, f_path='')
86 86 add_new = '<a href="%s">[%s]</a>' % (url_, _('click here to add new file'))
87 87 h.flash(h.literal(_('There are no files yet %s') % add_new),
88 88 category='warning')
89 89 redirect(h.url('summary_home', repo_name=repo_name))
90 90
91 91 except RepositoryError, e:
92 92 h.flash(str(e), category='warning')
93 93 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
94 94
95 95 def __get_filenode_or_redirect(self, repo_name, cs, path):
96 96 """
97 97 Returns file_node, if error occurs or given path is directory,
98 98 it'll redirect to top level path
99 99
100 100 :param repo_name: repo_name
101 101 :param cs: given changeset
102 102 :param path: path to lookup
103 103 """
104 104
105 105 try:
106 106 file_node = cs.get_node(path)
107 107 if file_node.is_dir():
108 108 raise RepositoryError('given path is a directory')
109 109 except RepositoryError, e:
110 110 h.flash(str(e), category='warning')
111 111 redirect(h.url('files_home', repo_name=repo_name,
112 112 revision=cs.raw_id))
113 113
114 114 return file_node
115 115
116 116 @LoginRequired()
117 117 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
118 118 'repository.admin')
119 119 def index(self, repo_name, revision, f_path, annotate=False):
120 120 # redirect to given revision from form if given
121 121 post_revision = request.POST.get('at_rev', None)
122 122 if post_revision:
123 123 cs = self.__get_cs_or_redirect(post_revision, repo_name)
124 124 redirect(url('files_home', repo_name=c.repo_name,
125 125 revision=cs.raw_id, f_path=f_path))
126 126
127 127 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
128 128 c.branch = request.GET.get('branch', None)
129 129 c.f_path = f_path
130 130 c.annotate = annotate
131 131 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
132 132 cur_rev = c.changeset.revision
133 133
134 134 # prev link
135 135 try:
136 136 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
137 137 c.url_prev = url('files_home', repo_name=c.repo_name,
138 138 revision=prev_rev.raw_id, f_path=f_path)
139 139 if c.branch:
140 140 c.url_prev += '?branch=%s' % c.branch
141 141 except (ChangesetDoesNotExistError, VCSError):
142 142 c.url_prev = '#'
143 143
144 144 # next link
145 145 try:
146 146 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
147 147 c.url_next = url('files_home', repo_name=c.repo_name,
148 148 revision=next_rev.raw_id, f_path=f_path)
149 149 if c.branch:
150 150 c.url_next += '?branch=%s' % c.branch
151 151 except (ChangesetDoesNotExistError, VCSError):
152 152 c.url_next = '#'
153 153
154 154 # files or dirs
155 155 try:
156 156 c.file = c.changeset.get_node(f_path)
157 157
158 158 if c.file.is_file():
159 159 c.load_full_history = False
160 160 file_last_cs = c.file.last_changeset
161 161 c.file_changeset = (c.changeset
162 162 if c.changeset.revision < file_last_cs.revision
163 163 else file_last_cs)
164 164 #determine if we're on branch head
165 165 _branches = c.rhodecode_repo.branches
166 c.on_branch_head = revision in _branches.keys() + _branches.values()
166 c.on_branch_head = revision in _branches.keys() + _branches.values()
167 167 _hist = []
168 168 c.file_history = []
169 169 if c.load_full_history:
170 170 c.file_history, _hist = self._get_node_history(c.changeset, f_path)
171 171
172 172 c.authors = []
173 173 for a in set([x.author for x in _hist]):
174 174 c.authors.append((h.email(a), h.person(a)))
175 175 else:
176 176 c.authors = c.file_history = []
177 177 except RepositoryError, e:
178 178 h.flash(str(e), category='warning')
179 179 redirect(h.url('files_home', repo_name=repo_name,
180 180 revision='tip'))
181 181
182 182 if request.environ.get('HTTP_X_PARTIAL_XHR'):
183 183 return render('files/files_ypjax.html')
184 184
185 185 return render('files/files.html')
186 186
187 187 def history(self, repo_name, revision, f_path, annotate=False):
188 188 if request.environ.get('HTTP_X_PARTIAL_XHR'):
189 189 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
190 190 c.f_path = f_path
191 191 c.annotate = annotate
192 192 c.file = c.changeset.get_node(f_path)
193 193 if c.file.is_file():
194 194 file_last_cs = c.file.last_changeset
195 195 c.file_changeset = (c.changeset
196 196 if c.changeset.revision < file_last_cs.revision
197 197 else file_last_cs)
198 198 c.file_history, _hist = self._get_node_history(c.changeset, f_path)
199 199 c.authors = []
200 200 for a in set([x.author for x in _hist]):
201 201 c.authors.append((h.email(a), h.person(a)))
202 202 return render('files/files_history_box.html')
203 203
204 204 @LoginRequired()
205 205 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
206 206 'repository.admin')
207 207 def rawfile(self, repo_name, revision, f_path):
208 208 cs = self.__get_cs_or_redirect(revision, repo_name)
209 209 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
210 210
211 211 response.content_disposition = 'attachment; filename=%s' % \
212 212 safe_str(f_path.split(Repository.url_sep())[-1])
213 213
214 214 response.content_type = file_node.mimetype
215 215 return file_node.content
216 216
217 217 @LoginRequired()
218 218 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
219 219 'repository.admin')
220 220 def raw(self, repo_name, revision, f_path):
221 221 cs = self.__get_cs_or_redirect(revision, repo_name)
222 222 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
223 223
224 224 raw_mimetype_mapping = {
225 225 # map original mimetype to a mimetype used for "show as raw"
226 226 # you can also provide a content-disposition to override the
227 227 # default "attachment" disposition.
228 228 # orig_type: (new_type, new_dispo)
229 229
230 230 # show images inline:
231 231 'image/x-icon': ('image/x-icon', 'inline'),
232 232 'image/png': ('image/png', 'inline'),
233 233 'image/gif': ('image/gif', 'inline'),
234 234 'image/jpeg': ('image/jpeg', 'inline'),
235 235 'image/svg+xml': ('image/svg+xml', 'inline'),
236 236 }
237 237
238 238 mimetype = file_node.mimetype
239 239 try:
240 240 mimetype, dispo = raw_mimetype_mapping[mimetype]
241 241 except KeyError:
242 242 # we don't know anything special about this, handle it safely
243 243 if file_node.is_binary:
244 244 # do same as download raw for binary files
245 245 mimetype, dispo = 'application/octet-stream', 'attachment'
246 246 else:
247 247 # do not just use the original mimetype, but force text/plain,
248 248 # otherwise it would serve text/html and that might be unsafe.
249 249 # Note: underlying vcs library fakes text/plain mimetype if the
250 250 # mimetype can not be determined and it thinks it is not
251 251 # binary.This might lead to erroneous text display in some
252 252 # cases, but helps in other cases, like with text files
253 253 # without extension.
254 254 mimetype, dispo = 'text/plain', 'inline'
255 255
256 256 if dispo == 'attachment':
257 257 dispo = 'attachment; filename=%s' % \
258 258 safe_str(f_path.split(os.sep)[-1])
259 259
260 260 response.content_disposition = dispo
261 261 response.content_type = mimetype
262 262 return file_node.content
263 263
264 264 @LoginRequired()
265 265 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
266 266 def edit(self, repo_name, revision, f_path):
267 267 repo = c.rhodecode_db_repo
268 268 if repo.enable_locking and repo.locked[0]:
269 269 h.flash(_('This repository is has been locked by %s on %s')
270 270 % (h.person_by_id(repo.locked[0]),
271 271 h.fmt_date(h.time_to_datetime(repo.locked[1]))),
272 272 'warning')
273 273 return redirect(h.url('files_home',
274 274 repo_name=repo_name, revision='tip'))
275 275
276 276 # check if revision is a branch identifier- basically we cannot
277 277 # create multiple heads via file editing
278 278 _branches = repo.scm_instance.branches
279 279 # check if revision is a branch name or branch hash
280 280 if revision not in _branches.keys() + _branches.values():
281 281 h.flash(_('You can only edit files with revision '
282 282 'being a valid branch '), category='warning')
283 283 return redirect(h.url('files_home',
284 284 repo_name=repo_name, revision='tip',
285 285 f_path=f_path))
286 286
287 287 r_post = request.POST
288 288
289 289 c.cs = self.__get_cs_or_redirect(revision, repo_name)
290 290 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
291 291
292 292 if c.file.is_binary:
293 293 return redirect(url('files_home', repo_name=c.repo_name,
294 294 revision=c.cs.raw_id, f_path=f_path))
295 295 c.default_message = _('Edited file %s via RhodeCode') % (f_path)
296 296 c.f_path = f_path
297 297
298 298 if r_post:
299 299
300 300 old_content = c.file.content
301 301 sl = old_content.splitlines(1)
302 302 first_line = sl[0] if sl else ''
303 303 # modes: 0 - Unix, 1 - Mac, 2 - DOS
304 304 mode = detect_mode(first_line, 0)
305 305 content = convert_line_endings(r_post.get('content'), mode)
306 306
307 307 message = r_post.get('message') or c.default_message
308 308 author = self.rhodecode_user.full_contact
309 309
310 310 if content == old_content:
311 311 h.flash(_('No changes'),
312 312 category='warning')
313 313 return redirect(url('changeset_home', repo_name=c.repo_name,
314 314 revision='tip'))
315 315 try:
316 316 self.scm_model.commit_change(repo=c.rhodecode_repo,
317 317 repo_name=repo_name, cs=c.cs,
318 318 user=self.rhodecode_user,
319 319 author=author, message=message,
320 320 content=content, f_path=f_path)
321 321 h.flash(_('Successfully committed to %s') % f_path,
322 322 category='success')
323 323
324 324 except Exception:
325 325 log.error(traceback.format_exc())
326 326 h.flash(_('Error occurred during commit'), category='error')
327 327 return redirect(url('changeset_home',
328 328 repo_name=c.repo_name, revision='tip'))
329 329
330 330 return render('files/files_edit.html')
331 331
332 332 @LoginRequired()
333 333 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
334 334 def add(self, repo_name, revision, f_path):
335 335
336 336 repo = Repository.get_by_repo_name(repo_name)
337 337 if repo.enable_locking and repo.locked[0]:
338 338 h.flash(_('This repository is has been locked by %s on %s')
339 339 % (h.person_by_id(repo.locked[0]),
340 340 h.fmt_date(h.time_to_datetime(repo.locked[1]))),
341 341 'warning')
342 342 return redirect(h.url('files_home',
343 343 repo_name=repo_name, revision='tip'))
344 344
345 345 r_post = request.POST
346 346 c.cs = self.__get_cs_or_redirect(revision, repo_name,
347 347 redirect_after=False)
348 348 if c.cs is None:
349 349 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
350 350 c.default_message = (_('Added file via RhodeCode'))
351 351 c.f_path = f_path
352 352
353 353 if r_post:
354 354 unix_mode = 0
355 355 content = convert_line_endings(r_post.get('content'), unix_mode)
356 356
357 357 message = r_post.get('message') or c.default_message
358 358 location = r_post.get('location')
359 359 filename = r_post.get('filename')
360 360 file_obj = r_post.get('upload_file', None)
361 361
362 362 if file_obj is not None and hasattr(file_obj, 'filename'):
363 363 filename = file_obj.filename
364 364 content = file_obj.file
365 365
366 366 node_path = os.path.join(location, filename)
367 367 author = self.rhodecode_user.full_contact
368 368
369 369 if not content:
370 370 h.flash(_('No content'), category='warning')
371 371 return redirect(url('changeset_home', repo_name=c.repo_name,
372 372 revision='tip'))
373 373 if not filename:
374 374 h.flash(_('No filename'), category='warning')
375 375 return redirect(url('changeset_home', repo_name=c.repo_name,
376 376 revision='tip'))
377 377
378 378 try:
379 379 self.scm_model.create_node(repo=c.rhodecode_repo,
380 380 repo_name=repo_name, cs=c.cs,
381 381 user=self.rhodecode_user,
382 382 author=author, message=message,
383 383 content=content, f_path=node_path)
384 384 h.flash(_('Successfully committed to %s') % node_path,
385 385 category='success')
386 386 except NodeAlreadyExistsError, e:
387 387 h.flash(_(e), category='error')
388 388 except Exception:
389 389 log.error(traceback.format_exc())
390 390 h.flash(_('Error occurred during commit'), category='error')
391 391 return redirect(url('changeset_home',
392 392 repo_name=c.repo_name, revision='tip'))
393 393
394 394 return render('files/files_add.html')
395 395
396 396 @LoginRequired()
397 397 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
398 398 'repository.admin')
399 399 def archivefile(self, repo_name, fname):
400 400
401 401 fileformat = None
402 402 revision = None
403 403 ext = None
404 404 subrepos = request.GET.get('subrepos') == 'true'
405 405
406 406 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
407 407 archive_spec = fname.split(ext_data[1])
408 408 if len(archive_spec) == 2 and archive_spec[1] == '':
409 409 fileformat = a_type or ext_data[1]
410 410 revision = archive_spec[0]
411 411 ext = ext_data[1]
412 412
413 413 try:
414 414 dbrepo = RepoModel().get_by_repo_name(repo_name)
415 415 if dbrepo.enable_downloads is False:
416 416 return _('downloads disabled')
417 417
418 418 if c.rhodecode_repo.alias == 'hg':
419 419 # patch and reset hooks section of UI config to not run any
420 420 # hooks on fetching archives with subrepos
421 421 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
422 422 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
423 423
424 424 cs = c.rhodecode_repo.get_changeset(revision)
425 425 content_type = settings.ARCHIVE_SPECS[fileformat][0]
426 426 except ChangesetDoesNotExistError:
427 427 return _('Unknown revision %s') % revision
428 428 except EmptyRepositoryError:
429 429 return _('Empty repository')
430 430 except (ImproperArchiveTypeError, KeyError):
431 431 return _('Unknown archive type')
432 432
433 433 fd, archive = tempfile.mkstemp()
434 434 t = open(archive, 'wb')
435 435 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
436 436 t.close()
437 437
438 438 def get_chunked_archive(archive):
439 439 stream = open(archive, 'rb')
440 440 while True:
441 441 data = stream.read(16 * 1024)
442 442 if not data:
443 443 stream.close()
444 444 os.close(fd)
445 445 os.remove(archive)
446 446 break
447 447 yield data
448 448
449 449 response.content_disposition = str('attachment; filename=%s-%s%s' \
450 450 % (repo_name, revision[:12], ext))
451 451 response.content_type = str(content_type)
452 452 return get_chunked_archive(archive)
453 453
454 454 @LoginRequired()
455 455 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
456 456 'repository.admin')
457 457 def diff(self, repo_name, f_path):
458 458 ignore_whitespace = request.GET.get('ignorews') == '1'
459 459 line_context = request.GET.get('context', 3)
460 460 diff1 = request.GET.get('diff1', '')
461 461 diff2 = request.GET.get('diff2', '')
462 462 c.action = request.GET.get('diff')
463 463 c.no_changes = diff1 == diff2
464 464 c.f_path = f_path
465 465 c.big_diff = False
466 466 c.anchor_url = anchor_url
467 467 c.ignorews_url = _ignorews_url
468 468 c.context_url = _context_url
469 469 c.changes = OrderedDict()
470 470 c.changes[diff2] = []
471 471
472 472 #special case if we want a show rev only, it's impl here
473 473 #to reduce JS and callbacks
474 474
475 475 if request.GET.get('show_rev'):
476 476 if str2bool(request.GET.get('annotate', 'False')):
477 477 _url = url('files_annotate_home', repo_name=c.repo_name,
478 478 revision=diff1, f_path=c.f_path)
479 479 else:
480 480 _url = url('files_home', repo_name=c.repo_name,
481 481 revision=diff1, f_path=c.f_path)
482 482
483 483 return redirect(_url)
484 484 try:
485 485 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
486 486 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
487 487 try:
488 488 node1 = c.changeset_1.get_node(f_path)
489 489 except NodeDoesNotExistError:
490 490 c.changeset_1 = EmptyChangeset(cs=diff1,
491 491 revision=c.changeset_1.revision,
492 492 repo=c.rhodecode_repo)
493 493 node1 = FileNode(f_path, '', changeset=c.changeset_1)
494 494 else:
495 495 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
496 496 node1 = FileNode(f_path, '', changeset=c.changeset_1)
497 497
498 498 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
499 499 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
500 500 try:
501 501 node2 = c.changeset_2.get_node(f_path)
502 502 except NodeDoesNotExistError:
503 503 c.changeset_2 = EmptyChangeset(cs=diff2,
504 504 revision=c.changeset_2.revision,
505 505 repo=c.rhodecode_repo)
506 506 node2 = FileNode(f_path, '', changeset=c.changeset_2)
507 507 else:
508 508 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
509 509 node2 = FileNode(f_path, '', changeset=c.changeset_2)
510 510 except (RepositoryError, NodeError):
511 511 log.error(traceback.format_exc())
512 512 return redirect(url('files_home', repo_name=c.repo_name,
513 513 f_path=f_path))
514 514
515 515 if c.action == 'download':
516 516 _diff = diffs.get_gitdiff(node1, node2,
517 517 ignore_whitespace=ignore_whitespace,
518 518 context=line_context)
519 519 diff = diffs.DiffProcessor(_diff, format='gitdiff')
520 520
521 521 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
522 522 response.content_type = 'text/plain'
523 523 response.content_disposition = (
524 524 'attachment; filename=%s' % diff_name
525 525 )
526 526 return diff.as_raw()
527 527
528 528 elif c.action == 'raw':
529 529 _diff = diffs.get_gitdiff(node1, node2,
530 530 ignore_whitespace=ignore_whitespace,
531 531 context=line_context)
532 532 diff = diffs.DiffProcessor(_diff, format='gitdiff')
533 533 response.content_type = 'text/plain'
534 534 return diff.as_raw()
535 535
536 536 else:
537 537 fid = h.FID(diff2, node2.path)
538 538 line_context_lcl = get_line_ctx(fid, request.GET)
539 539 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
540 540
541 541 lim = request.GET.get('fulldiff') or self.cut_off_limit
542 542 _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
543 543 filenode_new=node2,
544 544 cut_off_limit=lim,
545 545 ignore_whitespace=ign_whitespace_lcl,
546 546 line_context=line_context_lcl,
547 547 enable_comments=False)
548 548 op = ''
549 549 filename = node1.path
550 550 cs_changes = {
551 551 'fid': [cs1, cs2, op, filename, diff, st]
552 552 }
553 553 c.changes = cs_changes
554 554
555 555 return render('files/file_diff.html')
556 556
557 557 def _get_node_history(self, cs, f_path, changesets=None):
558 558 """
559 559 get changesets history for given node
560 560
561 561 :param cs: changeset to calculate history
562 562 :param f_path: path for node to calculate history for
563 563 :param changesets: if passed don't calculate history and take
564 564 changesets defined in this list
565 565 """
566 566 # calculate history based on tip
567 567 tip_cs = c.rhodecode_repo.get_changeset()
568 568 if changesets is None:
569 569 try:
570 570 changesets = tip_cs.get_file_history(f_path)
571 571 except (NodeDoesNotExistError, ChangesetError):
572 572 #this node is not present at tip !
573 573 changesets = cs.get_file_history(f_path)
574 574 hist_l = []
575 575
576 576 changesets_group = ([], _("Changesets"))
577 577 branches_group = ([], _("Branches"))
578 578 tags_group = ([], _("Tags"))
579 579 _hg = cs.repository.alias == 'hg'
580 580 for chs in changesets:
581 581 #_branch = '(%s)' % chs.branch if _hg else ''
582 582 _branch = chs.branch
583 583 n_desc = 'r%s:%s (%s)' % (chs.revision, chs.short_id, _branch)
584 584 changesets_group[0].append((chs.raw_id, n_desc,))
585 585 hist_l.append(changesets_group)
586 586
587 587 for name, chs in c.rhodecode_repo.branches.items():
588 588 branches_group[0].append((chs, name),)
589 589 hist_l.append(branches_group)
590 590
591 591 for name, chs in c.rhodecode_repo.tags.items():
592 592 tags_group[0].append((chs, name),)
593 593 hist_l.append(tags_group)
594 594
595 595 return hist_l, changesets
596 596
597 597 @LoginRequired()
598 598 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
599 599 'repository.admin')
600 600 @jsonify
601 601 def nodelist(self, repo_name, revision, f_path):
602 602 if request.environ.get('HTTP_X_PARTIAL_XHR'):
603 603 cs = self.__get_cs_or_redirect(revision, repo_name)
604 604 _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
605 605 flat=False)
606 606 return {'nodes': _d + _f}
@@ -1,1984 +1,1984 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.db
4 4 ~~~~~~~~~~~~~~~~~~
5 5
6 6 Database Models for RhodeCode
7 7
8 8 :created_on: Apr 08, 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 os
27 27 import logging
28 28 import datetime
29 29 import traceback
30 30 import hashlib
31 31 import time
32 32 from collections import defaultdict
33 33
34 34 from sqlalchemy import *
35 35 from sqlalchemy.ext.hybrid import hybrid_property
36 36 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
37 37 from sqlalchemy.exc import DatabaseError
38 38 from beaker.cache import cache_region, region_invalidate
39 39 from webob.exc import HTTPNotFound
40 40
41 41 from pylons.i18n.translation import lazy_ugettext as _
42 42
43 43 from rhodecode.lib.vcs import get_backend
44 44 from rhodecode.lib.vcs.utils.helpers import get_scm
45 45 from rhodecode.lib.vcs.exceptions import VCSError
46 46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
47 47
48 48 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
49 49 safe_unicode, remove_suffix, remove_prefix
50 50 from rhodecode.lib.compat import json
51 51 from rhodecode.lib.caching_query import FromCache
52 52
53 53 from rhodecode.model.meta import Base, Session
54 54
55 55 URL_SEP = '/'
56 56 log = logging.getLogger(__name__)
57 57
58 58 #==============================================================================
59 59 # BASE CLASSES
60 60 #==============================================================================
61 61
62 62 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
63 63
64 64
65 65 class BaseModel(object):
66 66 """
67 67 Base Model for all classess
68 68 """
69 69
70 70 @classmethod
71 71 def _get_keys(cls):
72 72 """return column names for this model """
73 73 return class_mapper(cls).c.keys()
74 74
75 75 def get_dict(self):
76 76 """
77 77 return dict with keys and values corresponding
78 78 to this model data """
79 79
80 80 d = {}
81 81 for k in self._get_keys():
82 82 d[k] = getattr(self, k)
83 83
84 84 # also use __json__() if present to get additional fields
85 85 _json_attr = getattr(self, '__json__', None)
86 86 if _json_attr:
87 87 # update with attributes from __json__
88 88 if callable(_json_attr):
89 89 _json_attr = _json_attr()
90 90 for k, val in _json_attr.iteritems():
91 91 d[k] = val
92 92 return d
93 93
94 94 def get_appstruct(self):
95 95 """return list with keys and values tupples corresponding
96 96 to this model data """
97 97
98 98 l = []
99 99 for k in self._get_keys():
100 100 l.append((k, getattr(self, k),))
101 101 return l
102 102
103 103 def populate_obj(self, populate_dict):
104 104 """populate model with data from given populate_dict"""
105 105
106 106 for k in self._get_keys():
107 107 if k in populate_dict:
108 108 setattr(self, k, populate_dict[k])
109 109
110 110 @classmethod
111 111 def query(cls):
112 112 return Session().query(cls)
113 113
114 114 @classmethod
115 115 def get(cls, id_):
116 116 if id_:
117 117 return cls.query().get(id_)
118 118
119 119 @classmethod
120 120 def get_or_404(cls, id_):
121 121 try:
122 122 id_ = int(id_)
123 123 except (TypeError, ValueError):
124 124 raise HTTPNotFound
125 125
126 126 res = cls.query().get(id_)
127 127 if not res:
128 128 raise HTTPNotFound
129 129 return res
130 130
131 131 @classmethod
132 132 def getAll(cls):
133 133 return cls.query().all()
134 134
135 135 @classmethod
136 136 def delete(cls, id_):
137 137 obj = cls.query().get(id_)
138 138 Session().delete(obj)
139 139
140 140 def __repr__(self):
141 141 if hasattr(self, '__unicode__'):
142 142 # python repr needs to return str
143 143 return safe_str(self.__unicode__())
144 144 return '<DB:%s>' % (self.__class__.__name__)
145 145
146 146
147 147 class RhodeCodeSetting(Base, BaseModel):
148 148 __tablename__ = 'rhodecode_settings'
149 149 __table_args__ = (
150 150 UniqueConstraint('app_settings_name'),
151 151 {'extend_existing': True, 'mysql_engine': 'InnoDB',
152 152 'mysql_charset': 'utf8'}
153 153 )
154 154 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
155 155 app_settings_name = Column("app_settings_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
156 156 _app_settings_value = Column("app_settings_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
157 157
158 158 def __init__(self, k='', v=''):
159 159 self.app_settings_name = k
160 160 self.app_settings_value = v
161 161
162 162 @validates('_app_settings_value')
163 163 def validate_settings_value(self, key, val):
164 164 assert type(val) == unicode
165 165 return val
166 166
167 167 @hybrid_property
168 168 def app_settings_value(self):
169 169 v = self._app_settings_value
170 170 if self.app_settings_name in ["ldap_active",
171 171 "default_repo_enable_statistics",
172 172 "default_repo_enable_locking",
173 173 "default_repo_private",
174 174 "default_repo_enable_downloads"]:
175 175 v = str2bool(v)
176 176 return v
177 177
178 178 @app_settings_value.setter
179 179 def app_settings_value(self, val):
180 180 """
181 181 Setter that will always make sure we use unicode in app_settings_value
182 182
183 183 :param val:
184 184 """
185 185 self._app_settings_value = safe_unicode(val)
186 186
187 187 def __unicode__(self):
188 188 return u"<%s('%s:%s')>" % (
189 189 self.__class__.__name__,
190 190 self.app_settings_name, self.app_settings_value
191 191 )
192 192
193 193 @classmethod
194 194 def get_by_name(cls, key):
195 195 return cls.query()\
196 196 .filter(cls.app_settings_name == key).scalar()
197 197
198 198 @classmethod
199 199 def get_by_name_or_create(cls, key):
200 200 res = cls.get_by_name(key)
201 201 if not res:
202 202 res = cls(key)
203 203 return res
204 204
205 205 @classmethod
206 206 def get_app_settings(cls, cache=False):
207 207
208 208 ret = cls.query()
209 209
210 210 if cache:
211 211 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
212 212
213 213 if not ret:
214 214 raise Exception('Could not get application settings !')
215 215 settings = {}
216 216 for each in ret:
217 217 settings['rhodecode_' + each.app_settings_name] = \
218 218 each.app_settings_value
219 219
220 220 return settings
221 221
222 222 @classmethod
223 223 def get_ldap_settings(cls, cache=False):
224 224 ret = cls.query()\
225 225 .filter(cls.app_settings_name.startswith('ldap_')).all()
226 226 fd = {}
227 227 for row in ret:
228 228 fd.update({row.app_settings_name: row.app_settings_value})
229 229
230 230 return fd
231 231
232 232 @classmethod
233 233 def get_default_repo_settings(cls, cache=False, strip_prefix=False):
234 234 ret = cls.query()\
235 235 .filter(cls.app_settings_name.startswith('default_')).all()
236 236 fd = {}
237 237 for row in ret:
238 238 key = row.app_settings_name
239 239 if strip_prefix:
240 240 key = remove_prefix(key, prefix='default_')
241 241 fd.update({key: row.app_settings_value})
242 242
243 243 return fd
244 244
245 245
246 246 class RhodeCodeUi(Base, BaseModel):
247 247 __tablename__ = 'rhodecode_ui'
248 248 __table_args__ = (
249 249 UniqueConstraint('ui_key'),
250 250 {'extend_existing': True, 'mysql_engine': 'InnoDB',
251 251 'mysql_charset': 'utf8'}
252 252 )
253 253
254 254 HOOK_UPDATE = 'changegroup.update'
255 255 HOOK_REPO_SIZE = 'changegroup.repo_size'
256 256 HOOK_PUSH = 'changegroup.push_logger'
257 257 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
258 258 HOOK_PULL = 'outgoing.pull_logger'
259 259 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
260 260
261 261 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
262 262 ui_section = Column("ui_section", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
263 263 ui_key = Column("ui_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
264 264 ui_value = Column("ui_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
265 265 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
266 266
267 267 @classmethod
268 268 def get_by_key(cls, key):
269 269 return cls.query().filter(cls.ui_key == key).scalar()
270 270
271 271 @classmethod
272 272 def get_builtin_hooks(cls):
273 273 q = cls.query()
274 274 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
275 275 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
276 276 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
277 277 return q.all()
278 278
279 279 @classmethod
280 280 def get_custom_hooks(cls):
281 281 q = cls.query()
282 282 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
283 283 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
284 284 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
285 285 q = q.filter(cls.ui_section == 'hooks')
286 286 return q.all()
287 287
288 288 @classmethod
289 289 def get_repos_location(cls):
290 290 return cls.get_by_key('/').ui_value
291 291
292 292 @classmethod
293 293 def create_or_update_hook(cls, key, val):
294 294 new_ui = cls.get_by_key(key) or cls()
295 295 new_ui.ui_section = 'hooks'
296 296 new_ui.ui_active = True
297 297 new_ui.ui_key = key
298 298 new_ui.ui_value = val
299 299
300 300 Session().add(new_ui)
301 301
302 302 def __repr__(self):
303 303 return '<DB:%s[%s:%s]>' % (self.__class__.__name__, self.ui_key,
304 304 self.ui_value)
305 305
306 306
307 307 class User(Base, BaseModel):
308 308 __tablename__ = 'users'
309 309 __table_args__ = (
310 310 UniqueConstraint('username'), UniqueConstraint('email'),
311 311 Index('u_username_idx', 'username'),
312 312 Index('u_email_idx', 'email'),
313 313 {'extend_existing': True, 'mysql_engine': 'InnoDB',
314 314 'mysql_charset': 'utf8'}
315 315 )
316 316 DEFAULT_USER = 'default'
317 317 DEFAULT_PERMISSIONS = [
318 318 'hg.register.manual_activate', 'hg.create.repository',
319 319 'hg.fork.repository', 'repository.read', 'group.read'
320 320 ]
321 321 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
322 322 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
323 323 password = Column("password", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
324 324 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
325 325 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
326 326 name = Column("firstname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
327 327 lastname = Column("lastname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
328 328 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
329 329 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
330 330 ldap_dn = Column("ldap_dn", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
331 331 api_key = Column("api_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
332 332 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
333 333
334 334 user_log = relationship('UserLog')
335 335 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
336 336
337 337 repositories = relationship('Repository')
338 338 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
339 339 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
340 340
341 341 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
342 342 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
343 343
344 344 group_member = relationship('UsersGroupMember', cascade='all')
345 345
346 346 notifications = relationship('UserNotification', cascade='all')
347 347 # notifications assigned to this user
348 348 user_created_notifications = relationship('Notification', cascade='all')
349 349 # comments created by this user
350 350 user_comments = relationship('ChangesetComment', cascade='all')
351 351 #extra emails for this user
352 352 user_emails = relationship('UserEmailMap', cascade='all')
353 353
354 354 @hybrid_property
355 355 def email(self):
356 356 return self._email
357 357
358 358 @email.setter
359 359 def email(self, val):
360 360 self._email = val.lower() if val else None
361 361
362 362 @property
363 363 def firstname(self):
364 364 # alias for future
365 365 return self.name
366 366
367 367 @property
368 368 def emails(self):
369 369 other = UserEmailMap.query().filter(UserEmailMap.user==self).all()
370 370 return [self.email] + [x.email for x in other]
371 371
372 372 @property
373 373 def ip_addresses(self):
374 374 ret = UserIpMap.query().filter(UserIpMap.user == self).all()
375 375 return [x.ip_addr for x in ret]
376 376
377 377 @property
378 378 def username_and_name(self):
379 379 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
380 380
381 381 @property
382 382 def full_name(self):
383 383 return '%s %s' % (self.firstname, self.lastname)
384 384
385 385 @property
386 386 def full_name_or_username(self):
387 387 return ('%s %s' % (self.firstname, self.lastname)
388 388 if (self.firstname and self.lastname) else self.username)
389 389
390 390 @property
391 391 def full_contact(self):
392 392 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
393 393
394 394 @property
395 395 def short_contact(self):
396 396 return '%s %s' % (self.firstname, self.lastname)
397 397
398 398 @property
399 399 def is_admin(self):
400 400 return self.admin
401 401
402 402 def __unicode__(self):
403 403 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
404 404 self.user_id, self.username)
405 405
406 406 @classmethod
407 407 def get_by_username(cls, username, case_insensitive=False, cache=False):
408 408 if case_insensitive:
409 409 q = cls.query().filter(cls.username.ilike(username))
410 410 else:
411 411 q = cls.query().filter(cls.username == username)
412 412
413 413 if cache:
414 414 q = q.options(FromCache(
415 415 "sql_cache_short",
416 416 "get_user_%s" % _hash_key(username)
417 417 )
418 418 )
419 419 return q.scalar()
420 420
421 421 @classmethod
422 422 def get_by_api_key(cls, api_key, cache=False):
423 423 q = cls.query().filter(cls.api_key == api_key)
424 424
425 425 if cache:
426 426 q = q.options(FromCache("sql_cache_short",
427 427 "get_api_key_%s" % api_key))
428 428 return q.scalar()
429 429
430 430 @classmethod
431 431 def get_by_email(cls, email, case_insensitive=False, cache=False):
432 432 if case_insensitive:
433 433 q = cls.query().filter(cls.email.ilike(email))
434 434 else:
435 435 q = cls.query().filter(cls.email == email)
436 436
437 437 if cache:
438 438 q = q.options(FromCache("sql_cache_short",
439 439 "get_email_key_%s" % email))
440 440
441 441 ret = q.scalar()
442 442 if ret is None:
443 443 q = UserEmailMap.query()
444 444 # try fetching in alternate email map
445 445 if case_insensitive:
446 446 q = q.filter(UserEmailMap.email.ilike(email))
447 447 else:
448 448 q = q.filter(UserEmailMap.email == email)
449 449 q = q.options(joinedload(UserEmailMap.user))
450 450 if cache:
451 451 q = q.options(FromCache("sql_cache_short",
452 452 "get_email_map_key_%s" % email))
453 453 ret = getattr(q.scalar(), 'user', None)
454 454
455 455 return ret
456 456
457 457 @classmethod
458 458 def get_from_cs_author(cls, author):
459 459 """
460 460 Tries to get User objects out of commit author string
461 461
462 462 :param author:
463 463 """
464 464 from rhodecode.lib.helpers import email, author_name
465 465 # Valid email in the attribute passed, see if they're in the system
466 466 _email = email(author)
467 467 if _email:
468 468 user = cls.get_by_email(_email, case_insensitive=True)
469 469 if user:
470 470 return user
471 471 # Maybe we can match by username?
472 472 _author = author_name(author)
473 473 user = cls.get_by_username(_author, case_insensitive=True)
474 474 if user:
475 475 return user
476 476
477 477 def update_lastlogin(self):
478 478 """Update user lastlogin"""
479 479 self.last_login = datetime.datetime.now()
480 480 Session().add(self)
481 481 log.debug('updated user %s lastlogin' % self.username)
482 482
483 483 def get_api_data(self):
484 484 """
485 485 Common function for generating user related data for API
486 486 """
487 487 user = self
488 488 data = dict(
489 489 user_id=user.user_id,
490 490 username=user.username,
491 491 firstname=user.name,
492 492 lastname=user.lastname,
493 493 email=user.email,
494 494 emails=user.emails,
495 495 api_key=user.api_key,
496 496 active=user.active,
497 497 admin=user.admin,
498 498 ldap_dn=user.ldap_dn,
499 499 last_login=user.last_login,
500 500 ip_addresses=user.ip_addresses
501 501 )
502 502 return data
503 503
504 504 def __json__(self):
505 505 data = dict(
506 506 full_name=self.full_name,
507 507 full_name_or_username=self.full_name_or_username,
508 508 short_contact=self.short_contact,
509 509 full_contact=self.full_contact
510 510 )
511 511 data.update(self.get_api_data())
512 512 return data
513 513
514 514
515 515 class UserEmailMap(Base, BaseModel):
516 516 __tablename__ = 'user_email_map'
517 517 __table_args__ = (
518 518 Index('uem_email_idx', 'email'),
519 519 UniqueConstraint('email'),
520 520 {'extend_existing': True, 'mysql_engine': 'InnoDB',
521 521 'mysql_charset': 'utf8'}
522 522 )
523 523 __mapper_args__ = {}
524 524
525 525 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
526 526 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
527 527 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
528 528 user = relationship('User', lazy='joined')
529 529
530 530 @validates('_email')
531 531 def validate_email(self, key, email):
532 532 # check if this email is not main one
533 533 main_email = Session().query(User).filter(User.email == email).scalar()
534 534 if main_email is not None:
535 535 raise AttributeError('email %s is present is user table' % email)
536 536 return email
537 537
538 538 @hybrid_property
539 539 def email(self):
540 540 return self._email
541 541
542 542 @email.setter
543 543 def email(self, val):
544 544 self._email = val.lower() if val else None
545 545
546 546
547 547 class UserIpMap(Base, BaseModel):
548 548 __tablename__ = 'user_ip_map'
549 549 __table_args__ = (
550 550 UniqueConstraint('user_id', 'ip_addr'),
551 551 {'extend_existing': True, 'mysql_engine': 'InnoDB',
552 552 'mysql_charset': 'utf8'}
553 553 )
554 554 __mapper_args__ = {}
555 555
556 556 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
557 557 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
558 558 ip_addr = Column("ip_addr", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
559 559 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
560 560 user = relationship('User', lazy='joined')
561 561
562 562 @classmethod
563 563 def _get_ip_range(cls, ip_addr):
564 564 from rhodecode.lib import ipaddr
565 565 net = ipaddr.IPNetwork(address=ip_addr)
566 566 return [str(net.network), str(net.broadcast)]
567 567
568 568 def __json__(self):
569 569 return dict(
570 570 ip_addr=self.ip_addr,
571 571 ip_range=self._get_ip_range(self.ip_addr)
572 572 )
573 573
574 574
575 575 class UserLog(Base, BaseModel):
576 576 __tablename__ = 'user_logs'
577 577 __table_args__ = (
578 578 {'extend_existing': True, 'mysql_engine': 'InnoDB',
579 579 'mysql_charset': 'utf8'},
580 580 )
581 581 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
582 582 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
583 583 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
584 584 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
585 585 repository_name = Column("repository_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
586 586 user_ip = Column("user_ip", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
587 587 action = Column("action", UnicodeText(1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
588 588 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
589 589
590 590 @property
591 591 def action_as_day(self):
592 592 return datetime.date(*self.action_date.timetuple()[:3])
593 593
594 594 user = relationship('User')
595 595 repository = relationship('Repository', cascade='')
596 596
597 597
598 598 class UsersGroup(Base, BaseModel):
599 599 __tablename__ = 'users_groups'
600 600 __table_args__ = (
601 601 {'extend_existing': True, 'mysql_engine': 'InnoDB',
602 602 'mysql_charset': 'utf8'},
603 603 )
604 604
605 605 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
606 606 users_group_name = Column("users_group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
607 607 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
608 608 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
609 609
610 610 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
611 611 users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
612 612 users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
613 613
614 614 def __unicode__(self):
615 615 return u'<userGroup(%s)>' % (self.users_group_name)
616 616
617 617 @classmethod
618 618 def get_by_group_name(cls, group_name, cache=False,
619 619 case_insensitive=False):
620 620 if case_insensitive:
621 621 q = cls.query().filter(cls.users_group_name.ilike(group_name))
622 622 else:
623 623 q = cls.query().filter(cls.users_group_name == group_name)
624 624 if cache:
625 625 q = q.options(FromCache(
626 626 "sql_cache_short",
627 627 "get_user_%s" % _hash_key(group_name)
628 628 )
629 629 )
630 630 return q.scalar()
631 631
632 632 @classmethod
633 633 def get(cls, users_group_id, cache=False):
634 634 users_group = cls.query()
635 635 if cache:
636 636 users_group = users_group.options(FromCache("sql_cache_short",
637 637 "get_users_group_%s" % users_group_id))
638 638 return users_group.get(users_group_id)
639 639
640 640 def get_api_data(self):
641 641 users_group = self
642 642
643 643 data = dict(
644 644 users_group_id=users_group.users_group_id,
645 645 group_name=users_group.users_group_name,
646 646 active=users_group.users_group_active,
647 647 )
648 648
649 649 return data
650 650
651 651
652 652 class UsersGroupMember(Base, BaseModel):
653 653 __tablename__ = 'users_groups_members'
654 654 __table_args__ = (
655 655 {'extend_existing': True, 'mysql_engine': 'InnoDB',
656 656 'mysql_charset': 'utf8'},
657 657 )
658 658
659 659 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
660 660 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
661 661 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
662 662
663 663 user = relationship('User', lazy='joined')
664 664 users_group = relationship('UsersGroup')
665 665
666 666 def __init__(self, gr_id='', u_id=''):
667 667 self.users_group_id = gr_id
668 668 self.user_id = u_id
669 669
670 670
671 671 class Repository(Base, BaseModel):
672 672 __tablename__ = 'repositories'
673 673 __table_args__ = (
674 674 UniqueConstraint('repo_name'),
675 675 Index('r_repo_name_idx', 'repo_name'),
676 676 {'extend_existing': True, 'mysql_engine': 'InnoDB',
677 677 'mysql_charset': 'utf8'},
678 678 )
679 679
680 680 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
681 681 repo_name = Column("repo_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
682 682 clone_uri = Column("clone_uri", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
683 683 repo_type = Column("repo_type", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
684 684 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
685 685 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
686 686 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
687 687 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
688 688 description = Column("description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
689 689 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
690 690 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
691 691 landing_rev = Column("landing_revision", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
692 692 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
693 693 _locked = Column("locked", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
694 694 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
695 695
696 696 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
697 697 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
698 698
699 699 user = relationship('User')
700 700 fork = relationship('Repository', remote_side=repo_id)
701 701 group = relationship('RepoGroup')
702 702 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
703 703 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
704 704 stats = relationship('Statistics', cascade='all', uselist=False)
705 705
706 706 followers = relationship('UserFollowing',
707 707 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
708 708 cascade='all')
709 709
710 710 logs = relationship('UserLog')
711 711 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
712 712
713 713 pull_requests_org = relationship('PullRequest',
714 714 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
715 715 cascade="all, delete, delete-orphan")
716 716
717 717 pull_requests_other = relationship('PullRequest',
718 718 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
719 719 cascade="all, delete, delete-orphan")
720 720
721 721 def __unicode__(self):
722 722 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
723 723 self.repo_name)
724 724
725 725 @hybrid_property
726 726 def locked(self):
727 727 # always should return [user_id, timelocked]
728 728 if self._locked:
729 729 _lock_info = self._locked.split(':')
730 730 return int(_lock_info[0]), _lock_info[1]
731 731 return [None, None]
732 732
733 733 @locked.setter
734 734 def locked(self, val):
735 735 if val and isinstance(val, (list, tuple)):
736 736 self._locked = ':'.join(map(str, val))
737 737 else:
738 738 self._locked = None
739 739
740 740 @hybrid_property
741 741 def changeset_cache(self):
742 742 from rhodecode.lib.vcs.backends.base import EmptyChangeset
743 743 dummy = EmptyChangeset().__json__()
744 744 if not self._changeset_cache:
745 745 return dummy
746 746 try:
747 747 return json.loads(self._changeset_cache)
748 748 except TypeError:
749 749 return dummy
750 750
751 751 @changeset_cache.setter
752 752 def changeset_cache(self, val):
753 753 try:
754 754 self._changeset_cache = json.dumps(val)
755 755 except:
756 756 log.error(traceback.format_exc())
757 757
758 758 @classmethod
759 759 def url_sep(cls):
760 760 return URL_SEP
761 761
762 762 @classmethod
763 763 def normalize_repo_name(cls, repo_name):
764 764 """
765 765 Normalizes os specific repo_name to the format internally stored inside
766 766 dabatabase using URL_SEP
767 767
768 768 :param cls:
769 769 :param repo_name:
770 770 """
771 771 return cls.url_sep().join(repo_name.split(os.sep))
772 772
773 773 @classmethod
774 774 def get_by_repo_name(cls, repo_name):
775 775 q = Session().query(cls).filter(cls.repo_name == repo_name)
776 776 q = q.options(joinedload(Repository.fork))\
777 777 .options(joinedload(Repository.user))\
778 778 .options(joinedload(Repository.group))
779 779 return q.scalar()
780 780
781 781 @classmethod
782 782 def get_by_full_path(cls, repo_full_path):
783 783 repo_name = repo_full_path.split(cls.base_path(), 1)[-1]
784 784 repo_name = cls.normalize_repo_name(repo_name)
785 785 return cls.get_by_repo_name(repo_name.strip(URL_SEP))
786 786
787 787 @classmethod
788 788 def get_repo_forks(cls, repo_id):
789 789 return cls.query().filter(Repository.fork_id == repo_id)
790 790
791 791 @classmethod
792 792 def base_path(cls):
793 793 """
794 794 Returns base path when all repos are stored
795 795
796 796 :param cls:
797 797 """
798 798 q = Session().query(RhodeCodeUi)\
799 799 .filter(RhodeCodeUi.ui_key == cls.url_sep())
800 800 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
801 801 return q.one().ui_value
802 802
803 803 @property
804 804 def forks(self):
805 805 """
806 806 Return forks of this repo
807 807 """
808 808 return Repository.get_repo_forks(self.repo_id)
809 809
810 810 @property
811 811 def parent(self):
812 812 """
813 813 Returns fork parent
814 814 """
815 815 return self.fork
816 816
817 817 @property
818 818 def just_name(self):
819 819 return self.repo_name.split(Repository.url_sep())[-1]
820 820
821 821 @property
822 822 def groups_with_parents(self):
823 823 groups = []
824 824 if self.group is None:
825 825 return groups
826 826
827 827 cur_gr = self.group
828 828 groups.insert(0, cur_gr)
829 829 while 1:
830 830 gr = getattr(cur_gr, 'parent_group', None)
831 831 cur_gr = cur_gr.parent_group
832 832 if gr is None:
833 833 break
834 834 groups.insert(0, gr)
835 835
836 836 return groups
837 837
838 838 @property
839 839 def groups_and_repo(self):
840 840 return self.groups_with_parents, self.just_name
841 841
842 842 @LazyProperty
843 843 def repo_path(self):
844 844 """
845 845 Returns base full path for that repository means where it actually
846 846 exists on a filesystem
847 847 """
848 848 q = Session().query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
849 849 Repository.url_sep())
850 850 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
851 851 return q.one().ui_value
852 852
853 853 @property
854 854 def repo_full_path(self):
855 855 p = [self.repo_path]
856 856 # we need to split the name by / since this is how we store the
857 857 # names in the database, but that eventually needs to be converted
858 858 # into a valid system path
859 859 p += self.repo_name.split(Repository.url_sep())
860 860 return os.path.join(*p)
861 861
862 862 @property
863 863 def cache_keys(self):
864 864 """
865 865 Returns associated cache keys for that repo
866 866 """
867 867 return CacheInvalidation.query()\
868 868 .filter(CacheInvalidation.cache_args == self.repo_name)\
869 869 .order_by(CacheInvalidation.cache_key)\
870 870 .all()
871 871
872 872 def get_new_name(self, repo_name):
873 873 """
874 874 returns new full repository name based on assigned group and new new
875 875
876 876 :param group_name:
877 877 """
878 878 path_prefix = self.group.full_path_splitted if self.group else []
879 879 return Repository.url_sep().join(path_prefix + [repo_name])
880 880
881 881 @property
882 882 def _ui(self):
883 883 """
884 884 Creates an db based ui object for this repository
885 885 """
886 886 from rhodecode.lib.utils import make_ui
887 887 return make_ui('db', clear_session=False)
888 888
889 889 @classmethod
890 890 def inject_ui(cls, repo, extras={}):
891 891 from rhodecode.lib.vcs.backends.hg import MercurialRepository
892 892 from rhodecode.lib.vcs.backends.git import GitRepository
893 893 required = (MercurialRepository, GitRepository)
894 894 if not isinstance(repo, required):
895 895 raise Exception('repo must be instance of %s' % required)
896 896
897 897 # inject ui extra param to log this action via push logger
898 898 for k, v in extras.items():
899 899 repo._repo.ui.setconfig('rhodecode_extras', k, v)
900 900
901 901 @classmethod
902 902 def is_valid(cls, repo_name):
903 903 """
904 904 returns True if given repo name is a valid filesystem repository
905 905
906 906 :param cls:
907 907 :param repo_name:
908 908 """
909 909 from rhodecode.lib.utils import is_valid_repo
910 910
911 911 return is_valid_repo(repo_name, cls.base_path())
912 912
913 913 def get_api_data(self):
914 914 """
915 915 Common function for generating repo api data
916 916
917 917 """
918 918 repo = self
919 919 data = dict(
920 920 repo_id=repo.repo_id,
921 921 repo_name=repo.repo_name,
922 922 repo_type=repo.repo_type,
923 923 clone_uri=repo.clone_uri,
924 924 private=repo.private,
925 925 created_on=repo.created_on,
926 926 description=repo.description,
927 927 landing_rev=repo.landing_rev,
928 928 owner=repo.user.username,
929 929 fork_of=repo.fork.repo_name if repo.fork else None,
930 930 enable_statistics=repo.enable_statistics,
931 931 enable_locking=repo.enable_locking,
932 932 enable_downloads=repo.enable_downloads,
933 933 last_changeset=repo.changeset_cache
934 934 )
935 935
936 936 return data
937 937
938 938 @classmethod
939 939 def lock(cls, repo, user_id):
940 940 repo.locked = [user_id, time.time()]
941 941 Session().add(repo)
942 942 Session().commit()
943 943
944 944 @classmethod
945 945 def unlock(cls, repo):
946 946 repo.locked = None
947 947 Session().add(repo)
948 948 Session().commit()
949 949
950 950 @property
951 951 def last_db_change(self):
952 952 return self.updated_on
953 953
954 954 def clone_url(self, **override):
955 955 from pylons import url
956 956 from urlparse import urlparse
957 957 import urllib
958 958 parsed_url = urlparse(url('home', qualified=True))
959 959 default_clone_uri = '%(scheme)s://%(user)s%(pass)s%(netloc)s%(prefix)s%(path)s'
960 960 decoded_path = safe_unicode(urllib.unquote(parsed_url.path))
961 961 args = {
962 962 'user': '',
963 963 'pass': '',
964 964 'scheme': parsed_url.scheme,
965 965 'netloc': parsed_url.netloc,
966 966 'prefix': decoded_path,
967 967 'path': self.repo_name
968 968 }
969 969
970 970 args.update(override)
971 971 return default_clone_uri % args
972 972
973 973 #==========================================================================
974 974 # SCM PROPERTIES
975 975 #==========================================================================
976 976
977 977 def get_changeset(self, rev=None):
978 978 return get_changeset_safe(self.scm_instance, rev)
979 979
980 980 def get_landing_changeset(self):
981 981 """
982 982 Returns landing changeset, or if that doesn't exist returns the tip
983 983 """
984 984 cs = self.get_changeset(self.landing_rev) or self.get_changeset()
985 985 return cs
986 986
987 987 def update_changeset_cache(self, cs_cache=None):
988 988 """
989 989 Update cache of last changeset for repository, keys should be::
990 990
991 991 short_id
992 992 raw_id
993 993 revision
994 994 message
995 995 date
996 996 author
997 997
998 998 :param cs_cache:
999 999 """
1000 1000 from rhodecode.lib.vcs.backends.base import BaseChangeset
1001 1001 if cs_cache is None:
1002 1002 cs_cache = self.get_changeset()
1003 1003 if isinstance(cs_cache, BaseChangeset):
1004 1004 cs_cache = cs_cache.__json__()
1005 1005
1006 1006 if (cs_cache != self.changeset_cache
1007 1007 or not self.last_change
1008 1008 or not self.changeset_cache):
1009 1009 _default = datetime.datetime.fromtimestamp(0)
1010 1010 last_change = cs_cache.get('date') or self.last_change or _default
1011 1011 log.debug('updated repo %s with new cs cache %s' % (self, cs_cache))
1012 1012 self.updated_on = last_change
1013 1013 self.changeset_cache = cs_cache
1014 1014 Session().add(self)
1015 1015 Session().commit()
1016 1016 else:
1017 1017 log.debug('Skipping repo:%s already with latest changes' % self)
1018 1018
1019 1019 @property
1020 1020 def tip(self):
1021 1021 return self.get_changeset('tip')
1022 1022
1023 1023 @property
1024 1024 def author(self):
1025 1025 return self.tip.author
1026 1026
1027 1027 @property
1028 1028 def last_change(self):
1029 1029 return self.scm_instance.last_change
1030 1030
1031 1031 def get_comments(self, revisions=None):
1032 1032 """
1033 1033 Returns comments for this repository grouped by revisions
1034 1034
1035 1035 :param revisions: filter query by revisions only
1036 1036 """
1037 1037 cmts = ChangesetComment.query()\
1038 1038 .filter(ChangesetComment.repo == self)
1039 1039 if revisions:
1040 1040 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
1041 1041 grouped = defaultdict(list)
1042 1042 for cmt in cmts.all():
1043 1043 grouped[cmt.revision].append(cmt)
1044 1044 return grouped
1045 1045
1046 1046 def statuses(self, revisions=None):
1047 1047 """
1048 1048 Returns statuses for this repository
1049 1049
1050 1050 :param revisions: list of revisions to get statuses for
1051 1051 :type revisions: list
1052 1052 """
1053 1053
1054 1054 statuses = ChangesetStatus.query()\
1055 1055 .filter(ChangesetStatus.repo == self)\
1056 1056 .filter(ChangesetStatus.version == 0)
1057 1057 if revisions:
1058 1058 statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
1059 1059 grouped = {}
1060 1060
1061 1061 #maybe we have open new pullrequest without a status ?
1062 1062 stat = ChangesetStatus.STATUS_UNDER_REVIEW
1063 1063 status_lbl = ChangesetStatus.get_status_lbl(stat)
1064 1064 for pr in PullRequest.query().filter(PullRequest.org_repo == self).all():
1065 1065 for rev in pr.revisions:
1066 1066 pr_id = pr.pull_request_id
1067 1067 pr_repo = pr.other_repo.repo_name
1068 1068 grouped[rev] = [stat, status_lbl, pr_id, pr_repo]
1069 1069
1070 1070 for stat in statuses.all():
1071 1071 pr_id = pr_repo = None
1072 1072 if stat.pull_request:
1073 1073 pr_id = stat.pull_request.pull_request_id
1074 1074 pr_repo = stat.pull_request.other_repo.repo_name
1075 1075 grouped[stat.revision] = [str(stat.status), stat.status_lbl,
1076 1076 pr_id, pr_repo]
1077 1077 return grouped
1078 1078
1079 1079 def _repo_size(self):
1080 1080 from rhodecode.lib import helpers as h
1081 1081 log.debug('calculating repository size...')
1082 1082 return h.format_byte_size(self.scm_instance.size)
1083 1083
1084 1084 #==========================================================================
1085 1085 # SCM CACHE INSTANCE
1086 1086 #==========================================================================
1087 1087
1088 1088 @property
1089 1089 def invalidate(self):
1090 1090 return CacheInvalidation.invalidate(self.repo_name)
1091 1091
1092 1092 def set_invalidate(self):
1093 1093 """
1094 1094 set a cache for invalidation for this instance
1095 1095 """
1096 1096 CacheInvalidation.set_invalidate(repo_name=self.repo_name)
1097 1097
1098 1098 @LazyProperty
1099 1099 def scm_instance(self):
1100 1100 import rhodecode
1101 1101 full_cache = str2bool(rhodecode.CONFIG.get('vcs_full_cache'))
1102 1102 if full_cache:
1103 1103 return self.scm_instance_cached()
1104 1104 return self.__get_instance()
1105 1105
1106 1106 def scm_instance_cached(self, cache_map=None):
1107 1107 @cache_region('long_term')
1108 1108 def _c(repo_name):
1109 1109 return self.__get_instance()
1110 1110 rn = self.repo_name
1111 1111 log.debug('Getting cached instance of repo')
1112 1112
1113 1113 if cache_map:
1114 1114 # get using prefilled cache_map
1115 1115 invalidate_repo = cache_map[self.repo_name]
1116 1116 if invalidate_repo:
1117 1117 invalidate_repo = (None if invalidate_repo.cache_active
1118 1118 else invalidate_repo)
1119 1119 else:
1120 1120 # get from invalidate
1121 1121 invalidate_repo = self.invalidate
1122 1122
1123 1123 if invalidate_repo is not None:
1124 1124 region_invalidate(_c, None, rn)
1125 1125 # update our cache
1126 1126 CacheInvalidation.set_valid(invalidate_repo.cache_key)
1127 1127 return _c(rn)
1128 1128
1129 1129 def __get_instance(self):
1130 1130 repo_full_path = self.repo_full_path
1131 1131 try:
1132 1132 alias = get_scm(repo_full_path)[0]
1133 1133 log.debug('Creating instance of %s repository' % alias)
1134 1134 backend = get_backend(alias)
1135 1135 except VCSError:
1136 1136 log.error(traceback.format_exc())
1137 1137 log.error('Perhaps this repository is in db and not in '
1138 1138 'filesystem run rescan repositories with '
1139 1139 '"destroy old data " option from admin panel')
1140 1140 return
1141 1141
1142 1142 if alias == 'hg':
1143 1143
1144 1144 repo = backend(safe_str(repo_full_path), create=False,
1145 1145 baseui=self._ui)
1146 1146 # skip hidden web repository
1147 1147 if repo._get_hidden():
1148 1148 return
1149 1149 else:
1150 1150 repo = backend(repo_full_path, create=False)
1151 1151
1152 1152 return repo
1153 1153
1154 1154
1155 1155 class RepoGroup(Base, BaseModel):
1156 1156 __tablename__ = 'groups'
1157 1157 __table_args__ = (
1158 1158 UniqueConstraint('group_name', 'group_parent_id'),
1159 1159 CheckConstraint('group_id != group_parent_id'),
1160 1160 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1161 1161 'mysql_charset': 'utf8'},
1162 1162 )
1163 1163 __mapper_args__ = {'order_by': 'group_name'}
1164 1164
1165 1165 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1166 1166 group_name = Column("group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
1167 1167 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
1168 1168 group_description = Column("group_description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1169 1169 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
1170 1170
1171 1171 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
1172 1172 users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
1173 1173
1174 1174 parent_group = relationship('RepoGroup', remote_side=group_id)
1175 1175
1176 1176 def __init__(self, group_name='', parent_group=None):
1177 1177 self.group_name = group_name
1178 1178 self.parent_group = parent_group
1179 1179
1180 1180 def __unicode__(self):
1181 1181 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
1182 1182 self.group_name)
1183 1183
1184 1184 @classmethod
1185 1185 def groups_choices(cls, groups=None, show_empty_group=True):
1186 1186 from webhelpers.html import literal as _literal
1187 1187 if not groups:
1188 1188 groups = cls.query().all()
1189 1189
1190 1190 repo_groups = []
1191 1191 if show_empty_group:
1192 1192 repo_groups = [('-1', '-- no parent --')]
1193 1193 sep = ' &raquo; '
1194 1194 _name = lambda k: _literal(sep.join(k))
1195 1195
1196 1196 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
1197 1197 for x in groups])
1198 1198
1199 1199 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
1200 1200 return repo_groups
1201 1201
1202 1202 @classmethod
1203 1203 def url_sep(cls):
1204 1204 return URL_SEP
1205 1205
1206 1206 @classmethod
1207 1207 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
1208 1208 if case_insensitive:
1209 1209 gr = cls.query()\
1210 1210 .filter(cls.group_name.ilike(group_name))
1211 1211 else:
1212 1212 gr = cls.query()\
1213 1213 .filter(cls.group_name == group_name)
1214 1214 if cache:
1215 1215 gr = gr.options(FromCache(
1216 1216 "sql_cache_short",
1217 1217 "get_group_%s" % _hash_key(group_name)
1218 1218 )
1219 1219 )
1220 1220 return gr.scalar()
1221 1221
1222 1222 @property
1223 1223 def parents(self):
1224 1224 parents_recursion_limit = 5
1225 1225 groups = []
1226 1226 if self.parent_group is None:
1227 1227 return groups
1228 1228 cur_gr = self.parent_group
1229 1229 groups.insert(0, cur_gr)
1230 1230 cnt = 0
1231 1231 while 1:
1232 1232 cnt += 1
1233 1233 gr = getattr(cur_gr, 'parent_group', None)
1234 1234 cur_gr = cur_gr.parent_group
1235 1235 if gr is None:
1236 1236 break
1237 1237 if cnt == parents_recursion_limit:
1238 1238 # this will prevent accidental infinit loops
1239 1239 log.error('group nested more than %s' %
1240 1240 parents_recursion_limit)
1241 1241 break
1242 1242
1243 1243 groups.insert(0, gr)
1244 1244 return groups
1245 1245
1246 1246 @property
1247 1247 def children(self):
1248 1248 return RepoGroup.query().filter(RepoGroup.parent_group == self)
1249 1249
1250 1250 @property
1251 1251 def name(self):
1252 1252 return self.group_name.split(RepoGroup.url_sep())[-1]
1253 1253
1254 1254 @property
1255 1255 def full_path(self):
1256 1256 return self.group_name
1257 1257
1258 1258 @property
1259 1259 def full_path_splitted(self):
1260 1260 return self.group_name.split(RepoGroup.url_sep())
1261 1261
1262 1262 @property
1263 1263 def repositories(self):
1264 1264 return Repository.query()\
1265 1265 .filter(Repository.group == self)\
1266 1266 .order_by(Repository.repo_name)
1267 1267
1268 1268 @property
1269 1269 def repositories_recursive_count(self):
1270 1270 cnt = self.repositories.count()
1271 1271
1272 1272 def children_count(group):
1273 1273 cnt = 0
1274 1274 for child in group.children:
1275 1275 cnt += child.repositories.count()
1276 1276 cnt += children_count(child)
1277 1277 return cnt
1278 1278
1279 1279 return cnt + children_count(self)
1280 1280
1281 1281 def recursive_groups_and_repos(self):
1282 1282 """
1283 1283 Recursive return all groups, with repositories in those groups
1284 1284 """
1285 1285 all_ = []
1286 1286
1287 1287 def _get_members(root_gr):
1288 1288 for r in root_gr.repositories:
1289 1289 all_.append(r)
1290 1290 childs = root_gr.children.all()
1291 1291 if childs:
1292 1292 for gr in childs:
1293 1293 all_.append(gr)
1294 1294 _get_members(gr)
1295 1295
1296 1296 _get_members(self)
1297 1297 return [self] + all_
1298 1298
1299 1299 def get_new_name(self, group_name):
1300 1300 """
1301 1301 returns new full group name based on parent and new name
1302 1302
1303 1303 :param group_name:
1304 1304 """
1305 1305 path_prefix = (self.parent_group.full_path_splitted if
1306 1306 self.parent_group else [])
1307 1307 return RepoGroup.url_sep().join(path_prefix + [group_name])
1308 1308
1309 1309
1310 1310 class Permission(Base, BaseModel):
1311 1311 __tablename__ = 'permissions'
1312 1312 __table_args__ = (
1313 1313 Index('p_perm_name_idx', 'permission_name'),
1314 1314 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1315 1315 'mysql_charset': 'utf8'},
1316 1316 )
1317 1317 PERMS = [
1318 1318 ('repository.none', _('Repository no access')),
1319 1319 ('repository.read', _('Repository read access')),
1320 1320 ('repository.write', _('Repository write access')),
1321 1321 ('repository.admin', _('Repository admin access')),
1322 1322
1323 1323 ('group.none', _('Repositories Group no access')),
1324 1324 ('group.read', _('Repositories Group read access')),
1325 1325 ('group.write', _('Repositories Group write access')),
1326 1326 ('group.admin', _('Repositories Group admin access')),
1327 1327
1328 1328 ('hg.admin', _('RhodeCode Administrator')),
1329 1329 ('hg.create.none', _('Repository creation disabled')),
1330 1330 ('hg.create.repository', _('Repository creation enabled')),
1331 1331 ('hg.fork.none', _('Repository forking disabled')),
1332 1332 ('hg.fork.repository', _('Repository forking enabled')),
1333 1333 ('hg.register.none', _('Register disabled')),
1334 1334 ('hg.register.manual_activate', _('Register new user with RhodeCode '
1335 1335 'with manual activation')),
1336 1336
1337 1337 ('hg.register.auto_activate', _('Register new user with RhodeCode '
1338 1338 'with auto activation')),
1339 1339 ]
1340 1340
1341 1341 # defines which permissions are more important higher the more important
1342 1342 PERM_WEIGHTS = {
1343 1343 'repository.none': 0,
1344 1344 'repository.read': 1,
1345 1345 'repository.write': 3,
1346 1346 'repository.admin': 4,
1347 1347
1348 1348 'group.none': 0,
1349 1349 'group.read': 1,
1350 1350 'group.write': 3,
1351 1351 'group.admin': 4,
1352 1352
1353 1353 'hg.fork.none': 0,
1354 1354 'hg.fork.repository': 1,
1355 1355 'hg.create.none': 0,
1356 1356 'hg.create.repository':1
1357 1357 }
1358 1358
1359 1359 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1360 1360 permission_name = Column("permission_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1361 1361 permission_longname = Column("permission_longname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1362 1362
1363 1363 def __unicode__(self):
1364 1364 return u"<%s('%s:%s')>" % (
1365 1365 self.__class__.__name__, self.permission_id, self.permission_name
1366 1366 )
1367 1367
1368 1368 @classmethod
1369 1369 def get_by_key(cls, key):
1370 1370 return cls.query().filter(cls.permission_name == key).scalar()
1371 1371
1372 1372 @classmethod
1373 1373 def get_default_perms(cls, default_user_id):
1374 1374 q = Session().query(UserRepoToPerm, Repository, cls)\
1375 1375 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
1376 1376 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
1377 1377 .filter(UserRepoToPerm.user_id == default_user_id)
1378 1378
1379 1379 return q.all()
1380 1380
1381 1381 @classmethod
1382 1382 def get_default_group_perms(cls, default_user_id):
1383 1383 q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
1384 1384 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
1385 1385 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
1386 1386 .filter(UserRepoGroupToPerm.user_id == default_user_id)
1387 1387
1388 1388 return q.all()
1389 1389
1390 1390
1391 1391 class UserRepoToPerm(Base, BaseModel):
1392 1392 __tablename__ = 'repo_to_perm'
1393 1393 __table_args__ = (
1394 1394 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
1395 1395 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1396 1396 'mysql_charset': 'utf8'}
1397 1397 )
1398 1398 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1399 1399 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1400 1400 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1401 1401 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1402 1402
1403 1403 user = relationship('User')
1404 1404 repository = relationship('Repository')
1405 1405 permission = relationship('Permission')
1406 1406
1407 1407 @classmethod
1408 1408 def create(cls, user, repository, permission):
1409 1409 n = cls()
1410 1410 n.user = user
1411 1411 n.repository = repository
1412 1412 n.permission = permission
1413 1413 Session().add(n)
1414 1414 return n
1415 1415
1416 1416 def __unicode__(self):
1417 1417 return u'<user:%s => %s >' % (self.user, self.repository)
1418 1418
1419 1419
1420 1420 class UserToPerm(Base, BaseModel):
1421 1421 __tablename__ = 'user_to_perm'
1422 1422 __table_args__ = (
1423 1423 UniqueConstraint('user_id', 'permission_id'),
1424 1424 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1425 1425 'mysql_charset': 'utf8'}
1426 1426 )
1427 1427 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1428 1428 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1429 1429 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1430 1430
1431 1431 user = relationship('User')
1432 1432 permission = relationship('Permission', lazy='joined')
1433 1433
1434 1434
1435 1435 class UsersGroupRepoToPerm(Base, BaseModel):
1436 1436 __tablename__ = 'users_group_repo_to_perm'
1437 1437 __table_args__ = (
1438 1438 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
1439 1439 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1440 1440 'mysql_charset': 'utf8'}
1441 1441 )
1442 1442 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1443 1443 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1444 1444 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1445 1445 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1446 1446
1447 1447 users_group = relationship('UsersGroup')
1448 1448 permission = relationship('Permission')
1449 1449 repository = relationship('Repository')
1450 1450
1451 1451 @classmethod
1452 1452 def create(cls, users_group, repository, permission):
1453 1453 n = cls()
1454 1454 n.users_group = users_group
1455 1455 n.repository = repository
1456 1456 n.permission = permission
1457 1457 Session().add(n)
1458 1458 return n
1459 1459
1460 1460 def __unicode__(self):
1461 1461 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
1462 1462
1463 1463
1464 1464 class UsersGroupToPerm(Base, BaseModel):
1465 1465 __tablename__ = 'users_group_to_perm'
1466 1466 __table_args__ = (
1467 1467 UniqueConstraint('users_group_id', 'permission_id',),
1468 1468 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1469 1469 'mysql_charset': 'utf8'}
1470 1470 )
1471 1471 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1472 1472 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1473 1473 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1474 1474
1475 1475 users_group = relationship('UsersGroup')
1476 1476 permission = relationship('Permission')
1477 1477
1478 1478
1479 1479 class UserRepoGroupToPerm(Base, BaseModel):
1480 1480 __tablename__ = 'user_repo_group_to_perm'
1481 1481 __table_args__ = (
1482 1482 UniqueConstraint('user_id', 'group_id', 'permission_id'),
1483 1483 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1484 1484 'mysql_charset': 'utf8'}
1485 1485 )
1486 1486
1487 1487 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1488 1488 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1489 1489 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1490 1490 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1491 1491
1492 1492 user = relationship('User')
1493 1493 group = relationship('RepoGroup')
1494 1494 permission = relationship('Permission')
1495 1495
1496 1496
1497 1497 class UsersGroupRepoGroupToPerm(Base, BaseModel):
1498 1498 __tablename__ = 'users_group_repo_group_to_perm'
1499 1499 __table_args__ = (
1500 1500 UniqueConstraint('users_group_id', 'group_id'),
1501 1501 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1502 1502 'mysql_charset': 'utf8'}
1503 1503 )
1504 1504
1505 1505 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1506 1506 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1507 1507 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1508 1508 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1509 1509
1510 1510 users_group = relationship('UsersGroup')
1511 1511 permission = relationship('Permission')
1512 1512 group = relationship('RepoGroup')
1513 1513
1514 1514
1515 1515 class Statistics(Base, BaseModel):
1516 1516 __tablename__ = 'statistics'
1517 1517 __table_args__ = (
1518 1518 UniqueConstraint('repository_id'),
1519 1519 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1520 1520 'mysql_charset': 'utf8'}
1521 1521 )
1522 1522 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1523 1523 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1524 1524 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1525 1525 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1526 1526 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1527 1527 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1528 1528
1529 1529 repository = relationship('Repository', single_parent=True)
1530 1530
1531 1531
1532 1532 class UserFollowing(Base, BaseModel):
1533 1533 __tablename__ = 'user_followings'
1534 1534 __table_args__ = (
1535 1535 UniqueConstraint('user_id', 'follows_repository_id'),
1536 1536 UniqueConstraint('user_id', 'follows_user_id'),
1537 1537 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1538 1538 'mysql_charset': 'utf8'}
1539 1539 )
1540 1540
1541 1541 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1542 1542 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1543 1543 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1544 1544 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1545 1545 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1546 1546
1547 1547 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1548 1548
1549 1549 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1550 1550 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1551 1551
1552 1552 @classmethod
1553 1553 def get_repo_followers(cls, repo_id):
1554 1554 return cls.query().filter(cls.follows_repo_id == repo_id)
1555 1555
1556 1556
1557 1557 class CacheInvalidation(Base, BaseModel):
1558 1558 __tablename__ = 'cache_invalidation'
1559 1559 __table_args__ = (
1560 1560 UniqueConstraint('cache_key'),
1561 1561 Index('key_idx', 'cache_key'),
1562 1562 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1563 1563 'mysql_charset': 'utf8'},
1564 1564 )
1565 1565 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1566 1566 cache_key = Column("cache_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1567 1567 cache_args = Column("cache_args", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1568 1568 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1569 1569
1570 1570 def __init__(self, cache_key, cache_args=''):
1571 1571 self.cache_key = cache_key
1572 1572 self.cache_args = cache_args
1573 1573 self.cache_active = False
1574 1574
1575 1575 def __unicode__(self):
1576 1576 return u"<%s('%s:%s')>" % (self.__class__.__name__,
1577 1577 self.cache_id, self.cache_key)
1578 1578
1579 1579 @property
1580 1580 def prefix(self):
1581 1581 _split = self.cache_key.split(self.cache_args, 1)
1582 1582 if _split and len(_split) == 2:
1583 1583 return _split[0]
1584 1584 return ''
1585 1585
1586 1586 @classmethod
1587 1587 def clear_cache(cls):
1588 1588 cls.query().delete()
1589 1589
1590 1590 @classmethod
1591 1591 def _get_key(cls, key):
1592 1592 """
1593 1593 Wrapper for generating a key, together with a prefix
1594 1594
1595 1595 :param key:
1596 1596 """
1597 1597 import rhodecode
1598 1598 prefix = ''
1599 1599 org_key = key
1600 1600 iid = rhodecode.CONFIG.get('instance_id')
1601 1601 if iid:
1602 1602 prefix = iid
1603 1603
1604 1604 return "%s%s" % (prefix, key), prefix, org_key
1605 1605
1606 1606 @classmethod
1607 1607 def get_by_key(cls, key):
1608 1608 return cls.query().filter(cls.cache_key == key).scalar()
1609 1609
1610 1610 @classmethod
1611 1611 def get_by_repo_name(cls, repo_name):
1612 1612 return cls.query().filter(cls.cache_args == repo_name).all()
1613 1613
1614 1614 @classmethod
1615 1615 def _get_or_create_key(cls, key, repo_name, commit=True):
1616 1616 inv_obj = Session().query(cls).filter(cls.cache_key == key).scalar()
1617 1617 if not inv_obj:
1618 1618 try:
1619 1619 inv_obj = CacheInvalidation(key, repo_name)
1620 1620 Session().add(inv_obj)
1621 1621 if commit:
1622 1622 Session().commit()
1623 1623 except Exception:
1624 1624 log.error(traceback.format_exc())
1625 1625 Session().rollback()
1626 1626 return inv_obj
1627 1627
1628 1628 @classmethod
1629 1629 def invalidate(cls, key):
1630 1630 """
1631 1631 Returns Invalidation object if this given key should be invalidated
1632 1632 None otherwise. `cache_active = False` means that this cache
1633 1633 state is not valid and needs to be invalidated
1634 1634
1635 1635 :param key:
1636 1636 """
1637 1637 repo_name = key
1638 1638 repo_name = remove_suffix(repo_name, '_README')
1639 1639 repo_name = remove_suffix(repo_name, '_RSS')
1640 1640 repo_name = remove_suffix(repo_name, '_ATOM')
1641 1641
1642 1642 # adds instance prefix
1643 1643 key, _prefix, _org_key = cls._get_key(key)
1644 1644 inv = cls._get_or_create_key(key, repo_name)
1645 1645
1646 1646 if inv and inv.cache_active is False:
1647 1647 return inv
1648 1648
1649 1649 @classmethod
1650 1650 def set_invalidate(cls, key=None, repo_name=None):
1651 1651 """
1652 1652 Mark this Cache key for invalidation, either by key or whole
1653 1653 cache sets based on repo_name
1654 1654
1655 1655 :param key:
1656 1656 """
1657 1657 invalidated_keys = []
1658 1658 if key:
1659 1659 key, _prefix, _org_key = cls._get_key(key)
1660 1660 inv_objs = Session().query(cls).filter(cls.cache_key == key).all()
1661 1661 elif repo_name:
1662 1662 inv_objs = Session().query(cls).filter(cls.cache_args == repo_name).all()
1663 1663
1664 1664 try:
1665 1665 for inv_obj in inv_objs:
1666 1666 inv_obj.cache_active = False
1667 1667 log.debug('marking %s key for invalidation based on key=%s,repo_name=%s'
1668 1668 % (inv_obj, key, repo_name))
1669 1669 invalidated_keys.append(inv_obj.cache_key)
1670 1670 Session().add(inv_obj)
1671 1671 Session().commit()
1672 1672 except Exception:
1673 1673 log.error(traceback.format_exc())
1674 1674 Session().rollback()
1675 1675 return invalidated_keys
1676 1676
1677 1677 @classmethod
1678 1678 def set_valid(cls, key):
1679 1679 """
1680 1680 Mark this cache key as active and currently cached
1681 1681
1682 1682 :param key:
1683 1683 """
1684 1684 inv_obj = cls.get_by_key(key)
1685 1685 inv_obj.cache_active = True
1686 1686 Session().add(inv_obj)
1687 1687 Session().commit()
1688 1688
1689 1689 @classmethod
1690 1690 def get_cache_map(cls):
1691 1691
1692 1692 class cachemapdict(dict):
1693 1693
1694 1694 def __init__(self, *args, **kwargs):
1695 1695 fixkey = kwargs.get('fixkey')
1696 1696 if fixkey:
1697 1697 del kwargs['fixkey']
1698 1698 self.fixkey = fixkey
1699 1699 super(cachemapdict, self).__init__(*args, **kwargs)
1700 1700
1701 1701 def __getattr__(self, name):
1702 1702 key = name
1703 1703 if self.fixkey:
1704 1704 key, _prefix, _org_key = cls._get_key(key)
1705 1705 if key in self.__dict__:
1706 1706 return self.__dict__[key]
1707 1707 else:
1708 1708 return self[key]
1709 1709
1710 1710 def __getitem__(self, key):
1711 1711 if self.fixkey:
1712 1712 key, _prefix, _org_key = cls._get_key(key)
1713 1713 try:
1714 1714 return super(cachemapdict, self).__getitem__(key)
1715 1715 except KeyError:
1716 1716 return
1717 1717
1718 1718 cache_map = cachemapdict(fixkey=True)
1719 1719 for obj in cls.query().all():
1720 1720 cache_map[obj.cache_key] = cachemapdict(obj.get_dict())
1721 1721 return cache_map
1722 1722
1723 1723
1724 1724 class ChangesetComment(Base, BaseModel):
1725 1725 __tablename__ = 'changeset_comments'
1726 1726 __table_args__ = (
1727 1727 Index('cc_revision_idx', 'revision'),
1728 1728 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1729 1729 'mysql_charset': 'utf8'},
1730 1730 )
1731 1731 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1732 1732 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1733 1733 revision = Column('revision', String(40), nullable=True)
1734 1734 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1735 1735 line_no = Column('line_no', Unicode(10), nullable=True)
1736 1736 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
1737 1737 f_path = Column('f_path', Unicode(1000), nullable=True)
1738 1738 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1739 1739 text = Column('text', UnicodeText(25000), nullable=False)
1740 1740 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1741 1741 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1742 1742
1743 1743 author = relationship('User', lazy='joined')
1744 1744 repo = relationship('Repository')
1745 1745 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
1746 1746 pull_request = relationship('PullRequest', lazy='joined')
1747 1747
1748 1748 @classmethod
1749 1749 def get_users(cls, revision=None, pull_request_id=None):
1750 1750 """
1751 1751 Returns user associated with this ChangesetComment. ie those
1752 1752 who actually commented
1753 1753
1754 1754 :param cls:
1755 1755 :param revision:
1756 1756 """
1757 1757 q = Session().query(User)\
1758 1758 .join(ChangesetComment.author)
1759 1759 if revision:
1760 1760 q = q.filter(cls.revision == revision)
1761 1761 elif pull_request_id:
1762 1762 q = q.filter(cls.pull_request_id == pull_request_id)
1763 1763 return q.all()
1764 1764
1765 1765
1766 1766 class ChangesetStatus(Base, BaseModel):
1767 1767 __tablename__ = 'changeset_statuses'
1768 1768 __table_args__ = (
1769 1769 Index('cs_revision_idx', 'revision'),
1770 1770 Index('cs_version_idx', 'version'),
1771 1771 UniqueConstraint('repo_id', 'revision', 'version'),
1772 1772 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1773 1773 'mysql_charset': 'utf8'}
1774 1774 )
1775 1775 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1776 1776 STATUS_APPROVED = 'approved'
1777 1777 STATUS_REJECTED = 'rejected'
1778 1778 STATUS_UNDER_REVIEW = 'under_review'
1779 1779
1780 1780 STATUSES = [
1781 1781 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1782 1782 (STATUS_APPROVED, _("Approved")),
1783 1783 (STATUS_REJECTED, _("Rejected")),
1784 1784 (STATUS_UNDER_REVIEW, _("Under Review")),
1785 1785 ]
1786 1786
1787 1787 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1788 1788 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1789 1789 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1790 1790 revision = Column('revision', String(40), nullable=False)
1791 1791 status = Column('status', String(128), nullable=False, default=DEFAULT)
1792 1792 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1793 1793 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1794 1794 version = Column('version', Integer(), nullable=False, default=0)
1795 1795 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1796 1796
1797 1797 author = relationship('User', lazy='joined')
1798 1798 repo = relationship('Repository')
1799 1799 comment = relationship('ChangesetComment', lazy='joined')
1800 1800 pull_request = relationship('PullRequest', lazy='joined')
1801 1801
1802 1802 def __unicode__(self):
1803 1803 return u"<%s('%s:%s')>" % (
1804 1804 self.__class__.__name__,
1805 1805 self.status, self.author
1806 1806 )
1807 1807
1808 1808 @classmethod
1809 1809 def get_status_lbl(cls, value):
1810 1810 return dict(cls.STATUSES).get(value)
1811 1811
1812 1812 @property
1813 1813 def status_lbl(self):
1814 1814 return ChangesetStatus.get_status_lbl(self.status)
1815 1815
1816 1816
1817 1817 class PullRequest(Base, BaseModel):
1818 1818 __tablename__ = 'pull_requests'
1819 1819 __table_args__ = (
1820 1820 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1821 1821 'mysql_charset': 'utf8'},
1822 1822 )
1823 1823
1824 1824 STATUS_NEW = u'new'
1825 1825 STATUS_OPEN = u'open'
1826 1826 STATUS_CLOSED = u'closed'
1827 1827
1828 1828 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1829 1829 title = Column('title', Unicode(256), nullable=True)
1830 1830 description = Column('description', UnicodeText(10240), nullable=True)
1831 1831 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1832 1832 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1833 1833 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1834 1834 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1835 1835 _revisions = Column('revisions', UnicodeText(20500)) # 500 revisions max
1836 1836 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1837 1837 org_ref = Column('org_ref', Unicode(256), nullable=False)
1838 1838 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1839 1839 other_ref = Column('other_ref', Unicode(256), nullable=False)
1840 1840
1841 1841 @hybrid_property
1842 1842 def revisions(self):
1843 1843 return self._revisions.split(':')
1844 1844
1845 1845 @revisions.setter
1846 1846 def revisions(self, val):
1847 1847 self._revisions = ':'.join(val)
1848 1848
1849 1849 @property
1850 1850 def org_ref_parts(self):
1851 1851 return self.org_ref.split(':')
1852 1852
1853 1853 @property
1854 1854 def other_ref_parts(self):
1855 1855 return self.other_ref.split(':')
1856 1856
1857 1857 author = relationship('User', lazy='joined')
1858 1858 reviewers = relationship('PullRequestReviewers',
1859 1859 cascade="all, delete, delete-orphan")
1860 1860 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1861 1861 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1862 1862 statuses = relationship('ChangesetStatus')
1863 1863 comments = relationship('ChangesetComment',
1864 1864 cascade="all, delete, delete-orphan")
1865 1865
1866 1866 def is_closed(self):
1867 1867 return self.status == self.STATUS_CLOSED
1868 1868
1869 1869 @property
1870 1870 def last_review_status(self):
1871 return self.statuses[-1].status
1871 return self.statuses[-1].status
1872 1872
1873 1873 def __json__(self):
1874 1874 return dict(
1875 1875 revisions=self.revisions
1876 1876 )
1877 1877
1878 1878
1879 1879 class PullRequestReviewers(Base, BaseModel):
1880 1880 __tablename__ = 'pull_request_reviewers'
1881 1881 __table_args__ = (
1882 1882 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1883 1883 'mysql_charset': 'utf8'},
1884 1884 )
1885 1885
1886 1886 def __init__(self, user=None, pull_request=None):
1887 1887 self.user = user
1888 1888 self.pull_request = pull_request
1889 1889
1890 1890 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1891 1891 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1892 1892 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1893 1893
1894 1894 user = relationship('User')
1895 1895 pull_request = relationship('PullRequest')
1896 1896
1897 1897
1898 1898 class Notification(Base, BaseModel):
1899 1899 __tablename__ = 'notifications'
1900 1900 __table_args__ = (
1901 1901 Index('notification_type_idx', 'type'),
1902 1902 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1903 1903 'mysql_charset': 'utf8'},
1904 1904 )
1905 1905
1906 1906 TYPE_CHANGESET_COMMENT = u'cs_comment'
1907 1907 TYPE_MESSAGE = u'message'
1908 1908 TYPE_MENTION = u'mention'
1909 1909 TYPE_REGISTRATION = u'registration'
1910 1910 TYPE_PULL_REQUEST = u'pull_request'
1911 1911 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1912 1912
1913 1913 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1914 1914 subject = Column('subject', Unicode(512), nullable=True)
1915 1915 body = Column('body', UnicodeText(50000), nullable=True)
1916 1916 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1917 1917 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1918 1918 type_ = Column('type', Unicode(256))
1919 1919
1920 1920 created_by_user = relationship('User')
1921 1921 notifications_to_users = relationship('UserNotification', lazy='joined',
1922 1922 cascade="all, delete, delete-orphan")
1923 1923
1924 1924 @property
1925 1925 def recipients(self):
1926 1926 return [x.user for x in UserNotification.query()\
1927 1927 .filter(UserNotification.notification == self)\
1928 1928 .order_by(UserNotification.user_id.asc()).all()]
1929 1929
1930 1930 @classmethod
1931 1931 def create(cls, created_by, subject, body, recipients, type_=None):
1932 1932 if type_ is None:
1933 1933 type_ = Notification.TYPE_MESSAGE
1934 1934
1935 1935 notification = cls()
1936 1936 notification.created_by_user = created_by
1937 1937 notification.subject = subject
1938 1938 notification.body = body
1939 1939 notification.type_ = type_
1940 1940 notification.created_on = datetime.datetime.now()
1941 1941
1942 1942 for u in recipients:
1943 1943 assoc = UserNotification()
1944 1944 assoc.notification = notification
1945 1945 u.notifications.append(assoc)
1946 1946 Session().add(notification)
1947 1947 return notification
1948 1948
1949 1949 @property
1950 1950 def description(self):
1951 1951 from rhodecode.model.notification import NotificationModel
1952 1952 return NotificationModel().make_description(self)
1953 1953
1954 1954
1955 1955 class UserNotification(Base, BaseModel):
1956 1956 __tablename__ = 'user_to_notification'
1957 1957 __table_args__ = (
1958 1958 UniqueConstraint('user_id', 'notification_id'),
1959 1959 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1960 1960 'mysql_charset': 'utf8'}
1961 1961 )
1962 1962 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1963 1963 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1964 1964 read = Column('read', Boolean, default=False)
1965 1965 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1966 1966
1967 1967 user = relationship('User', lazy="joined")
1968 1968 notification = relationship('Notification', lazy="joined",
1969 1969 order_by=lambda: Notification.created_on.desc(),)
1970 1970
1971 1971 def mark_as_read(self):
1972 1972 self.read = True
1973 1973 Session().add(self)
1974 1974
1975 1975
1976 1976 class DbMigrateVersion(Base, BaseModel):
1977 1977 __tablename__ = 'db_migrate_version'
1978 1978 __table_args__ = (
1979 1979 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1980 1980 'mysql_charset': 'utf8'},
1981 1981 )
1982 1982 repository_id = Column('repository_id', String(250), primary_key=True)
1983 1983 repository_path = Column('repository_path', Text)
1984 1984 version = Column('version', Integer)
@@ -1,175 +1,173 b''
1 1 div.codeblock {
2 2 overflow: auto;
3 3 padding: 0px;
4 4 border: 1px solid #ccc;
5 5 background: #f8f8f8;
6 6 font-size: 100%;
7 7 line-height: 100%;
8 8 /* new */
9 9 line-height: 125%;
10 10 -webkit-border-radius: 4px;
11 11 -moz-border-radius: 4px;
12 border-radius: 4px;
12 border-radius: 4px;
13 13 }
14 14 div.codeblock .code-header{
15 border-bottom: 1px solid #CCCCCC;
16 background: #EEEEEE;
17 padding:10px 0 10px 0;
15 border-bottom: 1px solid #CCCCCC;
16 background: #EEEEEE;
17 padding:10px 0 10px 0;
18 18 }
19 19
20 20 div.codeblock .code-header .stats{
21 clear: both;
22 padding: 6px 8px 6px 10px;
23 border-bottom: 1px solid rgb(204, 204, 204);
24 height: 23px;
25 margin-bottom: 6px;
21 clear: both;
22 padding: 6px 8px 6px 10px;
23 border-bottom: 1px solid rgb(204, 204, 204);
24 height: 23px;
25 margin-bottom: 6px;
26 26 }
27 27
28 28 div.codeblock .code-header .stats .left{
29 float:left;
29 float:left;
30 30 }
31 31 div.codeblock .code-header .stats .left.img{
32 margin-top:-2px;
32 margin-top:-2px;
33 33 }
34 34 div.codeblock .code-header .stats .left.item{
35 float:left;
36 padding: 0 9px 0 9px;
37 border-right:1px solid #ccc;
35 float:left;
36 padding: 0 9px 0 9px;
37 border-right:1px solid #ccc;
38 38 }
39 39 div.codeblock .code-header .stats .left.item pre{
40
41 40 }
42 41 div.codeblock .code-header .stats .left.item.last{
43 border-right:none;
42 border-right:none;
44 43 }
45 44 div.codeblock .code-header .stats .buttons{
46 float:right;
47 padding-right:4px;
45 float:right;
46 padding-right:4px;
48 47 }
49 48
50 49 div.codeblock .code-header .author{
51 margin-left:25px;
52 font-weight: bold;
53 height: 25px;
50 margin-left:25px;
51 font-weight: bold;
52 height: 25px;
54 53 }
55 54 div.codeblock .code-header .author .user{
56 padding-top:3px;
55 padding-top:3px;
57 56 }
58 57 div.codeblock .code-header .commit{
59 margin-left:25px;
60 font-weight: normal;
61 white-space:pre;
58 margin-left:25px;
59 font-weight: normal;
60 white-space:pre;
62 61 }
63 62
64 63 div.codeblock .code-body table{
65 64 width: 0 !important;
66 65 border: 0px !important;
67 66 }
68 67 div.codeblock .code-body table td {
69 border: 0px !important;
68 border: 0px !important;
70 69 }
71 70 div.code-body {
72 background-color: #FFFFFF;
71 background-color: #FFFFFF;
73 72 }
74 73
75 74 div.codeblock .code-header .search-path {
76 padding: 0px 0px 0px 10px;
75 padding: 0px 0px 0px 10px;
77 76 }
78 77
79 78 div.search-code-body {
80 79 background-color: #FFFFFF;
81 80 padding: 5px 0px 5px 10px;
82 81 }
83 82
84 83 div.search-code-body pre .match{
85 background-color: #FAFFA6;
84 background-color: #FAFFA6;
86 85 }
87 86 div.search-code-body pre .break{
88 background-color: #DDE7EF;
89 width: 100%;
90 color: #747474;
91 display: block;
92
87 background-color: #DDE7EF;
88 width: 100%;
89 color: #747474;
90 display: block;
93 91 }
94 92 div.annotatediv{
95 margin-left:2px;
96 margin-right:4px;
93 margin-left:2px;
94 margin-right:4px;
97 95 }
98 96 .code-highlight {
99 97 padding: 0px;
100 98 margin-top: 5px;
101 99 margin-bottom: 5px;
102 100 border-left: 2px solid #ccc;
103 101 }
104 .code-highlight pre, .linenodiv pre {
105 padding: 5px;
102 .code-highlight pre, .linenodiv pre {
103 padding: 5px;
106 104 margin: 0;
107 105 }
108 .code-highlight pre div:target {
106 .code-highlight pre div:target {
109 107 background-color: #FFFFBE !important;
110 108 }
111
109
112 110 .linenos a { text-decoration: none; }
113 111
114 112 .code { display: block; }
115 113 .code-highlight .hll, .codehilite .hll { background-color: #ffffcc }
116 114 .code-highlight .c, .codehilite .c { color: #408080; font-style: italic } /* Comment */
117 115 .code-highlight .err, .codehilite .err { border: 1px solid #FF0000 } /* Error */
118 116 .code-highlight .k, .codehilite .k { color: #008000; font-weight: bold } /* Keyword */
119 117 .code-highlight .o, .codehilite .o { color: #666666 } /* Operator */
120 118 .code-highlight .cm, .codehilite .cm { color: #408080; font-style: italic } /* Comment.Multiline */
121 119 .code-highlight .cp, .codehilite .cp { color: #BC7A00 } /* Comment.Preproc */
122 120 .code-highlight .c1, .codehilite .c1 { color: #408080; font-style: italic } /* Comment.Single */
123 121 .code-highlight .cs, .codehilite .cs { color: #408080; font-style: italic } /* Comment.Special */
124 122 .code-highlight .gd, .codehilite .gd { color: #A00000 } /* Generic.Deleted */
125 123 .code-highlight .ge, .codehilite .ge { font-style: italic } /* Generic.Emph */
126 124 .code-highlight .gr, .codehilite .gr { color: #FF0000 } /* Generic.Error */
127 125 .code-highlight .gh, .codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */
128 126 .code-highlight .gi, .codehilite .gi { color: #00A000 } /* Generic.Inserted */
129 127 .code-highlight .go, .codehilite .go { color: #808080 } /* Generic.Output */
130 128 .code-highlight .gp, .codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
131 129 .code-highlight .gs, .codehilite .gs { font-weight: bold } /* Generic.Strong */
132 130 .code-highlight .gu, .codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
133 131 .code-highlight .gt, .codehilite .gt { color: #0040D0 } /* Generic.Traceback */
134 132 .code-highlight .kc, .codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
135 133 .code-highlight .kd, .codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
136 134 .code-highlight .kn, .codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
137 135 .code-highlight .kp, .codehilite .kp { color: #008000 } /* Keyword.Pseudo */
138 136 .code-highlight .kr, .codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
139 137 .code-highlight .kt, .codehilite .kt { color: #B00040 } /* Keyword.Type */
140 138 .code-highlight .m, .codehilite .m { color: #666666 } /* Literal.Number */
141 139 .code-highlight .s, .codehilite .s { color: #BA2121 } /* Literal.String */
142 140 .code-highlight .na, .codehilite .na { color: #7D9029 } /* Name.Attribute */
143 141 .code-highlight .nb, .codehilite .nb { color: #008000 } /* Name.Builtin */
144 142 .code-highlight .nc, .codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */
145 143 .code-highlight .no, .codehilite .no { color: #880000 } /* Name.Constant */
146 144 .code-highlight .nd, .codehilite .nd { color: #AA22FF } /* Name.Decorator */
147 145 .code-highlight .ni, .codehilite .ni { color: #999999; font-weight: bold } /* Name.Entity */
148 146 .code-highlight .ne, .codehilite .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
149 147 .code-highlight .nf, .codehilite .nf { color: #0000FF } /* Name.Function */
150 148 .code-highlight .nl, .codehilite .nl { color: #A0A000 } /* Name.Label */
151 149 .code-highlight .nn, .codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
152 150 .code-highlight .nt, .codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */
153 151 .code-highlight .nv, .codehilite .nv { color: #19177C } /* Name.Variable */
154 152 .code-highlight .ow, .codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
155 153 .code-highlight .w, .codehilite .w { color: #bbbbbb } /* Text.Whitespace */
156 154 .code-highlight .mf, .codehilite .mf { color: #666666 } /* Literal.Number.Float */
157 155 .code-highlight .mh, .codehilite .mh { color: #666666 } /* Literal.Number.Hex */
158 156 .code-highlight .mi, .codehilite .mi { color: #666666 } /* Literal.Number.Integer */
159 157 .code-highlight .mo, .codehilite .mo { color: #666666 } /* Literal.Number.Oct */
160 158 .code-highlight .sb, .codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */
161 159 .code-highlight .sc, .codehilite .sc { color: #BA2121 } /* Literal.String.Char */
162 160 .code-highlight .sd, .codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
163 161 .code-highlight .s2, .codehilite .s2 { color: #BA2121 } /* Literal.String.Double */
164 162 .code-highlight .se, .codehilite .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
165 163 .code-highlight .sh, .codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */
166 164 .code-highlight .si, .codehilite .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
167 165 .code-highlight .sx, .codehilite .sx { color: #008000 } /* Literal.String.Other */
168 166 .code-highlight .sr, .codehilite .sr { color: #BB6688 } /* Literal.String.Regex */
169 167 .code-highlight .s1, .codehilite .s1 { color: #BA2121 } /* Literal.String.Single */
170 168 .code-highlight .ss, .codehilite .ss { color: #19177C } /* Literal.String.Symbol */
171 169 .code-highlight .bp, .codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */
172 170 .code-highlight .vc, .codehilite .vc { color: #19177C } /* Name.Variable.Class */
173 171 .code-highlight .vg, .codehilite .vg { color: #19177C } /* Name.Variable.Global */
174 172 .code-highlight .vi, .codehilite .vi { color: #19177C } /* Name.Variable.Instance */
175 173 .code-highlight .il, .codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */
This diff has been collapsed as it changes many lines, (3590 lines changed) Show them Hide them
@@ -1,4881 +1,4873 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 {
3 border: 0;
4 outline: 0;
5 font-size: 100%;
6 vertical-align: baseline;
7 background: transparent;
8 margin: 0;
9 padding: 0;
2 {
3 border: 0;
4 outline: 0;
5 font-size: 100%;
6 vertical-align: baseline;
7 background: transparent;
8 margin: 0;
9 padding: 0;
10 10 }
11 11
12 12 body {
13 line-height: 1;
14 height: 100%;
15 background: url("../images/background.png") repeat scroll 0 0 #B0B0B0;
16 font-family: Lucida Grande, Verdana, Lucida Sans Regular,
17 Lucida Sans Unicode, Arial, sans-serif; font-size : 12px;
18 color: #000;
19 margin: 0;
20 padding: 0;
21 font-size: 12px;
13 line-height: 1;
14 height: 100%;
15 background: url("../images/background.png") repeat scroll 0 0 #B0B0B0;
16 font-family: Lucida Grande, Verdana, Lucida Sans Regular,
17 Lucida Sans Unicode, Arial, sans-serif; font-size : 12px;
18 color: #000;
19 margin: 0;
20 padding: 0;
21 font-size: 12px;
22 22 }
23 23
24 24 ol,ul {
25 list-style: none;
25 list-style: none;
26 26 }
27 27
28 28 blockquote,q {
29 quotes: none;
29 quotes: none;
30 30 }
31 31
32 32 blockquote:before,blockquote:after,q:before,q:after {
33 content: none;
33 content: none;
34 34 }
35 35
36 36 :focus {
37 outline: 0;
37 outline: 0;
38 38 }
39 39
40 40 del {
41 text-decoration: line-through;
41 text-decoration: line-through;
42 42 }
43 43
44 44 table {
45 border-collapse: collapse;
46 border-spacing: 0;
45 border-collapse: collapse;
46 border-spacing: 0;
47 47 }
48 48
49 49 html {
50 height: 100%;
50 height: 100%;
51 51 }
52 52
53 53 a {
54 color: #003367;
55 text-decoration: none;
56 cursor: pointer;
54 color: #003367;
55 text-decoration: none;
56 cursor: pointer;
57 57 }
58 58
59 59 a:hover {
60 color: #316293;
61 text-decoration: underline;
60 color: #316293;
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 color: #292929;
67 font-weight: 700;
66 color: #292929;
67 font-weight: 700;
68 68 }
69 69
70 70 h1,div.h1 {
71 font-size: 22px;
71 font-size: 22px;
72 72 }
73 73
74 74 h2,div.h2 {
75 font-size: 20px;
75 font-size: 20px;
76 76 }
77 77
78 78 h3,div.h3 {
79 font-size: 18px;
79 font-size: 18px;
80 80 }
81 81
82 82 h4,div.h4 {
83 font-size: 16px;
83 font-size: 16px;
84 84 }
85 85
86 86 h5,div.h5 {
87 font-size: 14px;
87 font-size: 14px;
88 88 }
89 89
90 90 h6,div.h6 {
91 font-size: 11px;
91 font-size: 11px;
92 92 }
93 93
94 94 ul.circle {
95 list-style-type: circle;
95 list-style-type: circle;
96 96 }
97 97
98 98 ul.disc {
99 list-style-type: disc;
99 list-style-type: disc;
100 100 }
101 101
102 102 ul.square {
103 list-style-type: square;
103 list-style-type: square;
104 104 }
105 105
106 106 ol.lower-roman {
107 list-style-type: lower-roman;
107 list-style-type: lower-roman;
108 108 }
109 109
110 110 ol.upper-roman {
111 list-style-type: upper-roman;
111 list-style-type: upper-roman;
112 112 }
113 113
114 114 ol.lower-alpha {
115 list-style-type: lower-alpha;
115 list-style-type: lower-alpha;
116 116 }
117 117
118 118 ol.upper-alpha {
119 list-style-type: upper-alpha;
119 list-style-type: upper-alpha;
120 120 }
121 121
122 122 ol.decimal {
123 list-style-type: decimal;
123 list-style-type: decimal;
124 124 }
125 125
126 126 div.color {
127 clear: both;
128 overflow: hidden;
129 position: absolute;
130 background: #FFF;
131 margin: 7px 0 0 60px;
132 padding: 1px 1px 1px 0;
127 clear: both;
128 overflow: hidden;
129 position: absolute;
130 background: #FFF;
131 margin: 7px 0 0 60px;
132 padding: 1px 1px 1px 0;
133 133 }
134 134
135 135 div.color a {
136 width: 15px;
137 height: 15px;
138 display: block;
139 float: left;
140 margin: 0 0 0 1px;
141 padding: 0;
136 width: 15px;
137 height: 15px;
138 display: block;
139 float: left;
140 margin: 0 0 0 1px;
141 padding: 0;
142 142 }
143 143
144 144 div.options {
145 clear: both;
146 overflow: hidden;
147 position: absolute;
148 background: #FFF;
149 margin: 7px 0 0 162px;
150 padding: 0;
145 clear: both;
146 overflow: hidden;
147 position: absolute;
148 background: #FFF;
149 margin: 7px 0 0 162px;
150 padding: 0;
151 151 }
152 152
153 153 div.options a {
154 height: 1%;
155 display: block;
156 text-decoration: none;
157 margin: 0;
158 padding: 3px 8px;
154 height: 1%;
155 display: block;
156 text-decoration: none;
157 margin: 0;
158 padding: 3px 8px;
159 159 }
160 160
161 161 .top-left-rounded-corner {
162 -webkit-border-top-left-radius: 8px;
163 -khtml-border-radius-topleft: 8px;
164 -moz-border-radius-topleft: 8px;
165 border-top-left-radius: 8px;
162 -webkit-border-top-left-radius: 8px;
163 -khtml-border-radius-topleft: 8px;
164 -moz-border-radius-topleft: 8px;
165 border-top-left-radius: 8px;
166 166 }
167 167
168 168 .top-right-rounded-corner {
169 -webkit-border-top-right-radius: 8px;
170 -khtml-border-radius-topright: 8px;
171 -moz-border-radius-topright: 8px;
172 border-top-right-radius: 8px;
169 -webkit-border-top-right-radius: 8px;
170 -khtml-border-radius-topright: 8px;
171 -moz-border-radius-topright: 8px;
172 border-top-right-radius: 8px;
173 173 }
174 174
175 175 .bottom-left-rounded-corner {
176 -webkit-border-bottom-left-radius: 8px;
177 -khtml-border-radius-bottomleft: 8px;
178 -moz-border-radius-bottomleft: 8px;
179 border-bottom-left-radius: 8px;
176 -webkit-border-bottom-left-radius: 8px;
177 -khtml-border-radius-bottomleft: 8px;
178 -moz-border-radius-bottomleft: 8px;
179 border-bottom-left-radius: 8px;
180 180 }
181 181
182 182 .bottom-right-rounded-corner {
183 -webkit-border-bottom-right-radius: 8px;
184 -khtml-border-radius-bottomright: 8px;
185 -moz-border-radius-bottomright: 8px;
186 border-bottom-right-radius: 8px;
183 -webkit-border-bottom-right-radius: 8px;
184 -khtml-border-radius-bottomright: 8px;
185 -moz-border-radius-bottomright: 8px;
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 color:#B9B9B9;
225 color:#B9B9B9;
226 226 }
227 227
228 228 a.permalink{
229 visibility: hidden;
229 visibility: hidden;
230 230 }
231 231
232 232 a.permalink:hover{
233 text-decoration: none;
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 margin: 0;
248 padding: 0 10px;
247 margin: 0;
248 padding: 0 10px;
249 249 }
250 250
251 251 #header ul#logged-user {
252 margin-bottom: 5px !important;
253 -webkit-border-radius: 0px 0px 8px 8px;
254 -khtml-border-radius: 0px 0px 8px 8px;
255 -moz-border-radius: 0px 0px 8px 8px;
256 border-radius: 0px 0px 8px 8px;
257 height: 37px;
258 background-color: #003B76;
252 margin-bottom: 5px !important;
253 -webkit-border-radius: 0px 0px 8px 8px;
254 -khtml-border-radius: 0px 0px 8px 8px;
255 -moz-border-radius: 0px 0px 8px 8px;
256 border-radius: 0px 0px 8px 8px;
257 height: 37px;
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 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
268 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
269 269 }
270 270
271 271 #header ul#logged-user li {
272 list-style: none;
273 float: left;
274 margin: 8px 0 0;
275 padding: 4px 12px;
276 border-left: 1px solid #316293;
272 list-style: none;
273 float: left;
274 margin: 8px 0 0;
275 padding: 4px 12px;
276 border-left: 1px solid #316293;
277 277 }
278 278
279 279 #header ul#logged-user li.first {
280 border-left: none;
281 margin: 4px;
280 border-left: none;
281 margin: 4px;
282 282 }
283 283
284 284 #header ul#logged-user li.first div.gravatar {
285 margin-top: -2px;
285 margin-top: -2px;
286 286 }
287 287
288 288 #header ul#logged-user li.first div.account {
289 padding-top: 4px;
290 float: left;
289 padding-top: 4px;
290 float: left;
291 291 }
292 292
293 293 #header ul#logged-user li.last {
294 border-right: none;
294 border-right: none;
295 295 }
296 296
297 297 #header ul#logged-user li a {
298 color: #fff;
299 font-weight: 700;
300 text-decoration: none;
298 color: #fff;
299 font-weight: 700;
300 text-decoration: none;
301 301 }
302 302
303 303 #header ul#logged-user li a:hover {
304 text-decoration: underline;
304 text-decoration: underline;
305 305 }
306 306
307 307 #header ul#logged-user li.highlight a {
308 color: #fff;
308 color: #fff;
309 309 }
310 310
311 311 #header ul#logged-user li.highlight a:hover {
312 color: #FFF;
312 color: #FFF;
313 313 }
314 314
315 315 #header #header-inner {
316 min-height: 44px;
317 clear: both;
318 position: relative;
316 min-height: 44px;
317 clear: both;
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 margin: 0;
330 padding: 0;
331 display: block;
332 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
333 -webkit-border-radius: 4px 4px 4px 4px;
334 -khtml-border-radius: 4px 4px 4px 4px;
335 -moz-border-radius: 4px 4px 4px 4px;
336 border-radius: 4px 4px 4px 4px;
329 margin: 0;
330 padding: 0;
331 display: block;
332 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
333 -webkit-border-radius: 4px 4px 4px 4px;
334 -khtml-border-radius: 4px 4px 4px 4px;
335 -moz-border-radius: 4px 4px 4px 4px;
336 border-radius: 4px 4px 4px 4px;
337 337 }
338 338 #header #header-inner.hover{
339 position: fixed !important;
340 width: 100% !important;
341 margin-left: -10px !important;
342 z-index: 10000;
339 position: fixed !important;
340 width: 100% !important;
341 margin-left: -10px !important;
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 border-radius: 0px 0px 0px 0px;
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 margin-top: -46px;
358 padding-top: 46px;
357 margin-top: -46px;
358 padding-top: 46px;
359 359 }
360 360
361 361 #header #header-inner #home a {
362 height: 40px;
363 width: 46px;
364 display: block;
365 background: url("../images/button_home.png");
366 background-position: 0 0;
367 margin: 0;
368 padding: 0;
362 height: 40px;
363 width: 46px;
364 display: block;
365 background: url("../images/button_home.png");
366 background-position: 0 0;
367 margin: 0;
368 padding: 0;
369 369 }
370 370
371 371 #header #header-inner #home a:hover {
372 background-position: 0 -40px;
372 background-position: 0 -40px;
373 373 }
374 374
375 375 #header #header-inner #logo {
376 float: left;
377 position: absolute;
376 float: left;
377 position: absolute;
378 378 }
379 379
380 380 #header #header-inner #logo h1 {
381 color: #FFF;
382 font-size: 20px;
383 margin: 12px 0 0 13px;
384 padding: 0;
381 color: #FFF;
382 font-size: 20px;
383 margin: 12px 0 0 13px;
384 padding: 0;
385 385 }
386 386
387 387 #header #header-inner #logo a {
388 color: #fff;
389 text-decoration: none;
388 color: #fff;
389 text-decoration: none;
390 390 }
391 391
392 392 #header #header-inner #logo a:hover {
393 color: #bfe3ff;
393 color: #bfe3ff;
394 394 }
395 395
396 396 #header #header-inner #quick,#header #header-inner #quick ul {
397 position: relative;
398 float: right;
399 list-style-type: none;
400 list-style-position: outside;
401 margin: 8px 8px 0 0;
402 padding: 0;
397 position: relative;
398 float: right;
399 list-style-type: none;
400 list-style-position: outside;
401 margin: 8px 8px 0 0;
402 padding: 0;
403 403 }
404 404
405 405 #header #header-inner #quick li {
406 position: relative;
407 float: left;
408 margin: 0 5px 0 0;
409 padding: 0;
406 position: relative;
407 float: left;
408 margin: 0 5px 0 0;
409 padding: 0;
410 410 }
411 411
412 412 #header #header-inner #quick li a.menu_link {
413 top: 0;
414 left: 0;
415 height: 1%;
416 display: block;
417 clear: both;
418 overflow: hidden;
419 color: #FFF;
420 font-weight: 700;
421 text-decoration: none;
422 background: #369;
423 padding: 0;
424 -webkit-border-radius: 4px 4px 4px 4px;
425 -khtml-border-radius: 4px 4px 4px 4px;
426 -moz-border-radius: 4px 4px 4px 4px;
427 border-radius: 4px 4px 4px 4px;
413 top: 0;
414 left: 0;
415 height: 1%;
416 display: block;
417 clear: both;
418 overflow: hidden;
419 color: #FFF;
420 font-weight: 700;
421 text-decoration: none;
422 background: #369;
423 padding: 0;
424 -webkit-border-radius: 4px 4px 4px 4px;
425 -khtml-border-radius: 4px 4px 4px 4px;
426 -moz-border-radius: 4px 4px 4px 4px;
427 border-radius: 4px 4px 4px 4px;
428 428 }
429 429
430 430 #header #header-inner #quick li span.short {
431 padding: 9px 6px 8px 6px;
431 padding: 9px 6px 8px 6px;
432 432 }
433 433
434 434 #header #header-inner #quick li span {
435 top: 0;
436 right: 0;
437 height: 1%;
438 display: block;
439 float: left;
440 border-left: 1px solid #3f6f9f;
441 margin: 0;
442 padding: 10px 12px 8px 10px;
435 top: 0;
436 right: 0;
437 height: 1%;
438 display: block;
439 float: left;
440 border-left: 1px solid #3f6f9f;
441 margin: 0;
442 padding: 10px 12px 8px 10px;
443 443 }
444 444
445 445 #header #header-inner #quick li span.normal {
446 border: none;
447 padding: 10px 12px 8px;
446 border: none;
447 padding: 10px 12px 8px;
448 448 }
449 449
450 450 #header #header-inner #quick li span.icon {
451 top: 0;
452 left: 0;
453 border-left: none;
454 border-right: 1px solid #2e5c89;
455 padding: 8px 6px 4px;
456 min-width: 16px;
457 min-height: 16px;
451 top: 0;
452 left: 0;
453 border-left: none;
454 border-right: 1px solid #2e5c89;
455 padding: 8px 6px 4px;
456 min-width: 16px;
457 min-height: 16px;
458 458 }
459 459
460 460 #header #header-inner #quick li span.icon_short {
461 top: 0;
462 left: 0;
463 border-left: none;
464 border-right: 1px solid #2e5c89;
465 padding: 8px 6px 4px;
461 top: 0;
462 left: 0;
463 border-left: none;
464 border-right: 1px solid #2e5c89;
465 padding: 8px 6px 4px;
466 466 }
467 467
468 468 #header #header-inner #quick li span.icon img,#header #header-inner #quick li span.icon_short img
469 {
470 margin: 0px -2px 0px 0px;
469 {
470 margin: 0px -2px 0px 0px;
471 471 }
472 472
473 473 #header #header-inner #quick li.current a,
474 474 #header #header-inner #quick li a:hover {
475 background: #4e4e4e no-repeat top left;
475 background: #4e4e4e no-repeat top left;
476 476 }
477 477
478 478 #header #header-inner #quick li.current a span,
479 479 #header #header-inner #quick li a:hover span {
480 border-left: 1px solid #545454;
480 border-left: 1px solid #545454;
481 481 }
482 482
483 483 #header #header-inner #quick li.current a span.icon,
484 484 #header #header-inner #quick li.current a span.icon_short,
485 485 #header #header-inner #quick li a:hover span.icon,
486 486 #header #header-inner #quick li a:hover span.icon_short
487 {
488 border-left: none;
489 border-right: 1px solid #464646;
487 {
488 border-left: none;
489 border-right: 1px solid #464646;
490 490 }
491 491
492 492 #header #header-inner #quick ul {
493 top: 29px;
494 right: 0;
495 min-width: 200px;
496 display: none;
497 position: absolute;
498 background: #FFF;
499 border: 1px solid #666;
500 border-top: 1px solid #003367;
501 z-index: 100;
502 margin: 0px 0px 0px 0px;
503 padding: 0;
493 top: 29px;
494 right: 0;
495 min-width: 200px;
496 display: none;
497 position: absolute;
498 background: #FFF;
499 border: 1px solid #666;
500 border-top: 1px solid #003367;
501 z-index: 100;
502 margin: 0px 0px 0px 0px;
503 padding: 0;
504 504 }
505 505
506 506 #header #header-inner #quick ul.repo_switcher {
507 max-height: 275px;
508 overflow-x: hidden;
509 overflow-y: auto;
507 max-height: 275px;
508 overflow-x: hidden;
509 overflow-y: auto;
510 510 }
511 511
512 512 #header #header-inner #quick ul.repo_switcher li.qfilter_rs {
513 float: none;
514 margin: 0;
515 border-bottom: 2px solid #003367;
513 float: none;
514 margin: 0;
515 border-bottom: 2px solid #003367;
516 516 }
517 517
518 518 #header #header-inner #quick .repo_switcher_type {
519 position: absolute;
520 left: 0;
521 top: 9px;
519 position: absolute;
520 left: 0;
521 top: 9px;
522 522 }
523 523
524 524 #header #header-inner #quick li ul li {
525 border-bottom: 1px solid #ddd;
525 border-bottom: 1px solid #ddd;
526 526 }
527 527
528 528 #header #header-inner #quick li ul li a {
529 width: 182px;
530 height: auto;
531 display: block;
532 float: left;
533 background: #FFF;
534 color: #003367;
535 font-weight: 400;
536 margin: 0;
537 padding: 7px 9px;
529 width: 182px;
530 height: auto;
531 display: block;
532 float: left;
533 background: #FFF;
534 color: #003367;
535 font-weight: 400;
536 margin: 0;
537 padding: 7px 9px;
538 538 }
539 539
540 540 #header #header-inner #quick li ul li a:hover {
541 color: #000;
542 background: #FFF;
541 color: #000;
542 background: #FFF;
543 543 }
544 544
545 545 #header #header-inner #quick ul ul {
546 top: auto;
546 top: auto;
547 547 }
548 548
549 549 #header #header-inner #quick li ul ul {
550 right: 200px;
551 max-height: 290px;
552 overflow: auto;
553 overflow-x: hidden;
554 white-space: normal;
550 right: 200px;
551 max-height: 290px;
552 overflow: auto;
553 overflow-x: hidden;
554 white-space: normal;
555 555 }
556 556
557 557 #header #header-inner #quick li ul li a.journal,#header #header-inner #quick li ul li a.journal:hover
558 {
559 background: url("../images/icons/book.png") no-repeat scroll 4px 9px
560 #FFF;
561 width: 167px;
562 margin: 0;
563 padding: 12px 9px 7px 24px;
558 {
559 background: url("../images/icons/book.png") no-repeat scroll 4px 9px
560 #FFF;
561 width: 167px;
562 margin: 0;
563 padding: 12px 9px 7px 24px;
564 564 }
565 565
566 566 #header #header-inner #quick li ul li a.private_repo,#header #header-inner #quick li ul li a.private_repo:hover
567 {
568 background: url("../images/icons/lock.png") no-repeat scroll 4px 9px
569 #FFF;
570 min-width: 167px;
571 margin: 0;
572 padding: 12px 9px 7px 24px;
567 {
568 background: url("../images/icons/lock.png") no-repeat scroll 4px 9px
569 #FFF;
570 min-width: 167px;
571 margin: 0;
572 padding: 12px 9px 7px 24px;
573 573 }
574 574
575 575 #header #header-inner #quick li ul li a.public_repo,#header #header-inner #quick li ul li a.public_repo:hover
576 {
577 background: url("../images/icons/lock_open.png") no-repeat scroll 4px
578 9px #FFF;
579 min-width: 167px;
580 margin: 0;
581 padding: 12px 9px 7px 24px;
576 {
577 background: url("../images/icons/lock_open.png") no-repeat scroll 4px
578 9px #FFF;
579 min-width: 167px;
580 margin: 0;
581 padding: 12px 9px 7px 24px;
582 582 }
583 583
584 584 #header #header-inner #quick li ul li a.hg,#header #header-inner #quick li ul li a.hg:hover
585 {
586 background: url("../images/icons/hgicon.png") no-repeat scroll 4px 9px
587 #FFF;
588 min-width: 167px;
589 margin: 0 0 0 14px;
590 padding: 12px 9px 7px 24px;
585 {
586 background: url("../images/icons/hgicon.png") no-repeat scroll 4px 9px
587 #FFF;
588 min-width: 167px;
589 margin: 0 0 0 14px;
590 padding: 12px 9px 7px 24px;
591 591 }
592 592
593 593 #header #header-inner #quick li ul li a.git,#header #header-inner #quick li ul li a.git:hover
594 {
595 background: url("../images/icons/giticon.png") no-repeat scroll 4px 9px
596 #FFF;
597 min-width: 167px;
598 margin: 0 0 0 14px;
599 padding: 12px 9px 7px 24px;
594 {
595 background: url("../images/icons/giticon.png") no-repeat scroll 4px 9px
596 #FFF;
597 min-width: 167px;
598 margin: 0 0 0 14px;
599 padding: 12px 9px 7px 24px;
600 600 }
601 601
602 602 #header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover
603 {
604 background: url("../images/icons/database_edit.png") no-repeat scroll
605 4px 9px #FFF;
606 width: 167px;
607 margin: 0;
608 padding: 12px 9px 7px 24px;
603 {
604 background: url("../images/icons/database_edit.png") no-repeat scroll
605 4px 9px #FFF;
606 width: 167px;
607 margin: 0;
608 padding: 12px 9px 7px 24px;
609 609 }
610 610
611 611 #header #header-inner #quick li ul li a.repos_groups,#header #header-inner #quick li ul li a.repos_groups:hover
612 {
613 background: url("../images/icons/database_link.png") no-repeat scroll
614 4px 9px #FFF;
615 width: 167px;
616 margin: 0;
617 padding: 12px 9px 7px 24px;
612 {
613 background: url("../images/icons/database_link.png") no-repeat scroll
614 4px 9px #FFF;
615 width: 167px;
616 margin: 0;
617 padding: 12px 9px 7px 24px;
618 618 }
619 619
620 620 #header #header-inner #quick li ul li a.users,#header #header-inner #quick li ul li a.users:hover
621 {
622 background: #FFF url("../images/icons/user_edit.png") no-repeat 4px 9px;
623 width: 167px;
624 margin: 0;
625 padding: 12px 9px 7px 24px;
621 {
622 background: #FFF url("../images/icons/user_edit.png") no-repeat 4px 9px;
623 width: 167px;
624 margin: 0;
625 padding: 12px 9px 7px 24px;
626 626 }
627 627
628 628 #header #header-inner #quick li ul li a.groups,#header #header-inner #quick li ul li a.groups:hover
629 {
630 background: #FFF url("../images/icons/group_edit.png") no-repeat 4px 9px;
631 width: 167px;
632 margin: 0;
633 padding: 12px 9px 7px 24px;
629 {
630 background: #FFF url("../images/icons/group_edit.png") no-repeat 4px 9px;
631 width: 167px;
632 margin: 0;
633 padding: 12px 9px 7px 24px;
634 634 }
635 635
636 636 #header #header-inner #quick li ul li a.defaults,#header #header-inner #quick li ul li a.defaults:hover
637 637 {
638 638 background: #FFF url("../images/icons/wrench.png") no-repeat 4px 9px;
639 639 width: 167px;
640 640 margin: 0;
641 641 padding: 12px 9px 7px 24px;
642 642 }
643 643
644 644 #header #header-inner #quick li ul li a.settings,#header #header-inner #quick li ul li a.settings:hover
645 {
646 background: #FFF url("../images/icons/cog.png") no-repeat 4px 9px;
647 width: 167px;
648 margin: 0;
649 padding: 12px 9px 7px 24px;
645 {
646 background: #FFF url("../images/icons/cog.png") no-repeat 4px 9px;
647 width: 167px;
648 margin: 0;
649 padding: 12px 9px 7px 24px;
650 650 }
651 651
652 652 #header #header-inner #quick li ul li a.permissions,#header #header-inner #quick li ul li a.permissions:hover
653 {
654 background: #FFF url("../images/icons/key.png") no-repeat 4px 9px;
655 width: 167px;
656 margin: 0;
657 padding: 12px 9px 7px 24px;
653 {
654 background: #FFF url("../images/icons/key.png") no-repeat 4px 9px;
655 width: 167px;
656 margin: 0;
657 padding: 12px 9px 7px 24px;
658 658 }
659 659
660 660 #header #header-inner #quick li ul li a.ldap,#header #header-inner #quick li ul li a.ldap:hover
661 {
662 background: #FFF url("../images/icons/server_key.png") no-repeat 4px 9px;
663 width: 167px;
664 margin: 0;
665 padding: 12px 9px 7px 24px;
661 {
662 background: #FFF url("../images/icons/server_key.png") no-repeat 4px 9px;
663 width: 167px;
664 margin: 0;
665 padding: 12px 9px 7px 24px;
666 666 }
667 667
668 668 #header #header-inner #quick li ul li a.fork,#header #header-inner #quick li ul li a.fork:hover
669 {
670 background: #FFF url("../images/icons/arrow_divide.png") no-repeat 4px
671 9px;
672 width: 167px;
673 margin: 0;
674 padding: 12px 9px 7px 24px;
669 {
670 background: #FFF url("../images/icons/arrow_divide.png") no-repeat 4px
671 9px;
672 width: 167px;
673 margin: 0;
674 padding: 12px 9px 7px 24px;
675 675 }
676 676
677 677 #header #header-inner #quick li ul li a.locking_add,#header #header-inner #quick li ul li a.locking_add:hover
678 678 {
679 679 background: #FFF url("../images/icons/lock_add.png") no-repeat 4px
680 680 9px;
681 681 width: 167px;
682 682 margin: 0;
683 683 padding: 12px 9px 7px 24px;
684 684 }
685 685
686 686 #header #header-inner #quick li ul li a.locking_del,#header #header-inner #quick li ul li a.locking_del:hover
687 687 {
688 688 background: #FFF url("../images/icons/lock_delete.png") no-repeat 4px
689 689 9px;
690 690 width: 167px;
691 691 margin: 0;
692 692 padding: 12px 9px 7px 24px;
693 693 }
694 694
695 695 #header #header-inner #quick li ul li a.pull_request,#header #header-inner #quick li ul li a.pull_request:hover
696 696 {
697 697 background: #FFF url("../images/icons/arrow_join.png") no-repeat 4px
698 698 9px;
699 699 width: 167px;
700 700 margin: 0;
701 701 padding: 12px 9px 7px 24px;
702 702 }
703 703
704 704 #header #header-inner #quick li ul li a.compare_request,#header #header-inner #quick li ul li a.compare_request:hover
705 705 {
706 706 background: #FFF url("../images/icons/arrow_inout.png") no-repeat 4px
707 707 9px;
708 708 width: 167px;
709 709 margin: 0;
710 710 padding: 12px 9px 7px 24px;
711 711 }
712 712
713 713 #header #header-inner #quick li ul li a.search,#header #header-inner #quick li ul li a.search:hover
714 {
715 background: #FFF url("../images/icons/search_16.png") no-repeat 4px 9px;
716 width: 167px;
717 margin: 0;
718 padding: 12px 9px 7px 24px;
714 {
715 background: #FFF url("../images/icons/search_16.png") no-repeat 4px 9px;
716 width: 167px;
717 margin: 0;
718 padding: 12px 9px 7px 24px;
719 719 }
720 720
721 721 #header #header-inner #quick li ul li a.delete,#header #header-inner #quick li ul li a.delete:hover
722 {
723 background: #FFF url("../images/icons/delete.png") no-repeat 4px 9px;
724 width: 167px;
725 margin: 0;
726 padding: 12px 9px 7px 24px;
722 {
723 background: #FFF url("../images/icons/delete.png") no-repeat 4px 9px;
724 width: 167px;
725 margin: 0;
726 padding: 12px 9px 7px 24px;
727 727 }
728 728
729 729 #header #header-inner #quick li ul li a.branches,#header #header-inner #quick li ul li a.branches:hover
730 {
731 background: #FFF url("../images/icons/arrow_branch.png") no-repeat 4px
732 9px;
733 width: 167px;
734 margin: 0;
735 padding: 12px 9px 7px 24px;
730 {
731 background: #FFF url("../images/icons/arrow_branch.png") no-repeat 4px
732 9px;
733 width: 167px;
734 margin: 0;
735 padding: 12px 9px 7px 24px;
736 736 }
737 737
738 738 #header #header-inner #quick li ul li a.tags,
739 739 #header #header-inner #quick li ul li a.tags:hover{
740 background: #FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
741 width: 167px;
742 margin: 0;
743 padding: 12px 9px 7px 24px;
740 background: #FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
741 width: 167px;
742 margin: 0;
743 padding: 12px 9px 7px 24px;
744 744 }
745 745
746 746 #header #header-inner #quick li ul li a.bookmarks,
747 747 #header #header-inner #quick li ul li a.bookmarks:hover{
748 748 background: #FFF url("../images/icons/tag_green.png") no-repeat 4px 9px;
749 749 width: 167px;
750 750 margin: 0;
751 751 padding: 12px 9px 7px 24px;
752 752 }
753 753
754 754 #header #header-inner #quick li ul li a.admin,
755 755 #header #header-inner #quick li ul li a.admin:hover{
756 background: #FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
757 width: 167px;
758 margin: 0;
759 padding: 12px 9px 7px 24px;
756 background: #FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
757 width: 167px;
758 margin: 0;
759 padding: 12px 9px 7px 24px;
760 760 }
761 761
762 762 .groups_breadcrumbs a {
763 color: #fff;
763 color: #fff;
764 764 }
765 765
766 766 .groups_breadcrumbs a:hover {
767 color: #bfe3ff;
768 text-decoration: none;
767 color: #bfe3ff;
768 text-decoration: none;
769 769 }
770 770
771 771 td.quick_repo_menu {
772 background: #FFF url("../images/vertical-indicator.png") 8px 50% no-repeat !important;
773 cursor: pointer;
774 width: 8px;
775 border: 1px solid transparent;
772 background: #FFF url("../images/vertical-indicator.png") 8px 50% no-repeat !important;
773 cursor: pointer;
774 width: 8px;
775 border: 1px solid transparent;
776 776 }
777 777
778 778 td.quick_repo_menu.active {
779 779 background: url("../images/dt-arrow-dn.png") no-repeat scroll 5px 50% #FFFFFF !important;
780 780 border: 1px solid #003367;
781 781 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
782 782 cursor: pointer;
783 783 }
784 784
785 785 td.quick_repo_menu .menu_items {
786 margin-top: 10px;
787 margin-left:-6px;
788 width: 150px;
789 position: absolute;
790 background-color: #FFF;
791 background: none repeat scroll 0 0 #FFFFFF;
792 border-color: #003367 #666666 #666666;
793 border-right: 1px solid #666666;
794 border-style: solid;
795 border-width: 1px;
796 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
797 border-top-style: none;
786 margin-top: 10px;
787 margin-left:-6px;
788 width: 150px;
789 position: absolute;
790 background-color: #FFF;
791 background: none repeat scroll 0 0 #FFFFFF;
792 border-color: #003367 #666666 #666666;
793 border-right: 1px solid #666666;
794 border-style: solid;
795 border-width: 1px;
796 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
797 border-top-style: none;
798 798 }
799 799
800 800 td.quick_repo_menu .menu_items li {
801 padding: 0 !important;
801 padding: 0 !important;
802 802 }
803 803
804 804 td.quick_repo_menu .menu_items a {
805 display: block;
806 padding: 4px 12px 4px 8px;
805 display: block;
806 padding: 4px 12px 4px 8px;
807 807 }
808 808
809 809 td.quick_repo_menu .menu_items a:hover {
810 background-color: #EEE;
811 text-decoration: none;
810 background-color: #EEE;
811 text-decoration: none;
812 812 }
813 813
814 814 td.quick_repo_menu .menu_items .icon img {
815 margin-bottom: -2px;
815 margin-bottom: -2px;
816 816 }
817 817
818 818 td.quick_repo_menu .menu_items.hidden {
819 display: none;
819 display: none;
820 820 }
821 821
822 822 .yui-dt-first th {
823 text-align: left;
823 text-align: left;
824 824 }
825 825
826 826 /*
827 827 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
828 828 Code licensed under the BSD License:
829 829 http://developer.yahoo.com/yui/license.html
830 830 version: 2.9.0
831 831 */
832 832 .yui-skin-sam .yui-dt-mask {
833 833 position: absolute;
834 834 z-index: 9500;
835 835 }
836 836 .yui-dt-tmp {
837 837 position: absolute;
838 838 left: -9000px;
839 839 }
840 840 .yui-dt-scrollable .yui-dt-bd { overflow: auto }
841 841 .yui-dt-scrollable .yui-dt-hd {
842 842 overflow: hidden;
843 843 position: relative;
844 844 }
845 845 .yui-dt-scrollable .yui-dt-bd thead tr,
846 846 .yui-dt-scrollable .yui-dt-bd thead th {
847 847 position: absolute;
848 848 left: -1500px;
849 849 }
850 850 .yui-dt-scrollable tbody { -moz-outline: 0 }
851 851 .yui-skin-sam thead .yui-dt-sortable { cursor: pointer }
852 852 .yui-skin-sam thead .yui-dt-draggable { cursor: move }
853 853 .yui-dt-coltarget {
854 854 position: absolute;
855 855 z-index: 999;
856 856 }
857 857 .yui-dt-hd { zoom: 1 }
858 858 th.yui-dt-resizeable .yui-dt-resizerliner { position: relative }
859 859 .yui-dt-resizer {
860 860 position: absolute;
861 861 right: 0;
862 862 bottom: 0;
863 863 height: 100%;
864 864 cursor: e-resize;
865 865 cursor: col-resize;
866 866 background-color: #CCC;
867 867 opacity: 0;
868 868 filter: alpha(opacity=0);
869 869 }
870 870 .yui-dt-resizerproxy {
871 871 visibility: hidden;
872 872 position: absolute;
873 873 z-index: 9000;
874 874 background-color: #CCC;
875 875 opacity: 0;
876 876 filter: alpha(opacity=0);
877 877 }
878 878 th.yui-dt-hidden .yui-dt-liner,
879 879 td.yui-dt-hidden .yui-dt-liner,
880 880 th.yui-dt-hidden .yui-dt-resizer { display: none }
881 881 .yui-dt-editor,
882 882 .yui-dt-editor-shim {
883 883 position: absolute;
884 884 z-index: 9000;
885 885 }
886 886 .yui-skin-sam .yui-dt table {
887 887 margin: 0;
888 888 padding: 0;
889 889 font-family: arial;
890 890 font-size: inherit;
891 891 border-collapse: separate;
892 892 *border-collapse: collapse;
893 893 border-spacing: 0;
894 894 border: 1px solid #7f7f7f;
895 895 }
896 896 .yui-skin-sam .yui-dt thead { border-spacing: 0 }
897 897 .yui-skin-sam .yui-dt caption {
898 898 color: #000;
899 899 font-size: 85%;
900 900 font-weight: normal;
901 901 font-style: italic;
902 902 line-height: 1;
903 903 padding: 1em 0;
904 904 text-align: center;
905 905 }
906 906 .yui-skin-sam .yui-dt th { background: #d8d8da url(../images/sprite.png) repeat-x 0 0 }
907 907 .yui-skin-sam .yui-dt th,
908 908 .yui-skin-sam .yui-dt th a {
909 909 font-weight: normal;
910 910 text-decoration: none;
911 911 color: #000;
912 912 vertical-align: bottom;
913 913 }
914 914 .yui-skin-sam .yui-dt th {
915 915 margin: 0;
916 916 padding: 0;
917 917 border: 0;
918 918 border-right: 1px solid #cbcbcb;
919 919 }
920 920 .yui-skin-sam .yui-dt tr.yui-dt-first td { border-top: 1px solid #7f7f7f }
921 921 .yui-skin-sam .yui-dt th .yui-dt-liner { white-space: nowrap }
922 922 .yui-skin-sam .yui-dt-liner {
923 923 margin: 0;
924 924 padding: 0;
925 925 }
926 926 .yui-skin-sam .yui-dt-coltarget {
927 927 width: 5px;
928 928 background-color: red;
929 929 }
930 930 .yui-skin-sam .yui-dt td {
931 931 margin: 0;
932 932 padding: 0;
933 933 border: 0;
934 934 border-right: 1px solid #cbcbcb;
935 935 text-align: left;
936 936 }
937 937 .yui-skin-sam .yui-dt-list td { border-right: 0 }
938 938 .yui-skin-sam .yui-dt-resizer { width: 6px }
939 939 .yui-skin-sam .yui-dt-mask {
940 940 background-color: #000;
941 941 opacity: .25;
942 942 filter: alpha(opacity=25);
943 943 }
944 944 .yui-skin-sam .yui-dt-message { background-color: #FFF }
945 945 .yui-skin-sam .yui-dt-scrollable table { border: 0 }
946 946 .yui-skin-sam .yui-dt-scrollable .yui-dt-hd {
947 947 border-left: 1px solid #7f7f7f;
948 948 border-top: 1px solid #7f7f7f;
949 949 border-right: 1px solid #7f7f7f;
950 950 }
951 951 .yui-skin-sam .yui-dt-scrollable .yui-dt-bd {
952 952 border-left: 1px solid #7f7f7f;
953 953 border-bottom: 1px solid #7f7f7f;
954 954 border-right: 1px solid #7f7f7f;
955 955 background-color: #FFF;
956 956 }
957 957 .yui-skin-sam .yui-dt-scrollable .yui-dt-data tr.yui-dt-last td { border-bottom: 1px solid #7f7f7f }
958 958 .yui-skin-sam th.yui-dt-asc,
959 959 .yui-skin-sam th.yui-dt-desc { background: url(../images/sprite.png) repeat-x 0 -100px }
960 960 .yui-skin-sam th.yui-dt-sortable .yui-dt-label { margin-right: 10px }
961 961 .yui-skin-sam th.yui-dt-asc .yui-dt-liner { background: url(../images/dt-arrow-up.png) no-repeat right }
962 962 .yui-skin-sam th.yui-dt-desc .yui-dt-liner { background: url(../images/dt-arrow-dn.png) no-repeat right }
963 963 tbody .yui-dt-editable { cursor: pointer }
964 964 .yui-dt-editor {
965 965 text-align: left;
966 966 background-color: #f2f2f2;
967 967 border: 1px solid #808080;
968 968 padding: 6px;
969 969 }
970 970 .yui-dt-editor label {
971 971 padding-left: 4px;
972 972 padding-right: 6px;
973 973 }
974 974 .yui-dt-editor .yui-dt-button {
975 975 padding-top: 6px;
976 976 text-align: right;
977 977 }
978 978 .yui-dt-editor .yui-dt-button button {
979 979 background: url(../images/sprite.png) repeat-x 0 0;
980 980 border: 1px solid #999;
981 981 width: 4em;
982 982 height: 1.8em;
983 983 margin-left: 6px;
984 984 }
985 985 .yui-dt-editor .yui-dt-button button.yui-dt-default {
986 986 background: url(../images/sprite.png) repeat-x 0 -1400px;
987 987 background-color: #5584e0;
988 988 border: 1px solid #304369;
989 989 color: #FFF;
990 990 }
991 991 .yui-dt-editor .yui-dt-button button:hover {
992 992 background: url(../images/sprite.png) repeat-x 0 -1300px;
993 993 color: #000;
994 994 }
995 995 .yui-dt-editor .yui-dt-button button:active {
996 996 background: url(../images/sprite.png) repeat-x 0 -1700px;
997 997 color: #000;
998 998 }
999 999 .yui-skin-sam tr.yui-dt-even { background-color: #FFF }
1000 1000 .yui-skin-sam tr.yui-dt-odd { background-color: #edf5ff }
1001 1001 .yui-skin-sam tr.yui-dt-even td.yui-dt-asc,
1002 1002 .yui-skin-sam tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
1003 1003 .yui-skin-sam tr.yui-dt-odd td.yui-dt-asc,
1004 1004 .yui-skin-sam tr.yui-dt-odd td.yui-dt-desc { background-color: #dbeaff }
1005 1005 .yui-skin-sam .yui-dt-list tr.yui-dt-even { background-color: #FFF }
1006 1006 .yui-skin-sam .yui-dt-list tr.yui-dt-odd { background-color: #FFF }
1007 1007 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-asc,
1008 1008 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
1009 1009 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-asc,
1010 1010 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-desc { background-color: #edf5ff }
1011 1011 .yui-skin-sam th.yui-dt-highlighted,
1012 1012 .yui-skin-sam th.yui-dt-highlighted a { background-color: #b2d2ff }
1013 1013 .yui-skin-sam tr.yui-dt-highlighted,
1014 1014 .yui-skin-sam tr.yui-dt-highlighted td.yui-dt-asc,
1015 1015 .yui-skin-sam tr.yui-dt-highlighted td.yui-dt-desc,
1016 1016 .yui-skin-sam tr.yui-dt-even td.yui-dt-highlighted,
1017 1017 .yui-skin-sam tr.yui-dt-odd td.yui-dt-highlighted {
1018 1018 cursor: pointer;
1019 1019 background-color: #b2d2ff;
1020 1020 }
1021 1021 .yui-skin-sam .yui-dt-list th.yui-dt-highlighted,
1022 1022 .yui-skin-sam .yui-dt-list th.yui-dt-highlighted a { background-color: #b2d2ff }
1023 1023 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted,
1024 1024 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-asc,
1025 1025 .yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-desc,
1026 1026 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-highlighted,
1027 1027 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-highlighted {
1028 1028 cursor: pointer;
1029 1029 background-color: #b2d2ff;
1030 1030 }
1031 1031 .yui-skin-sam th.yui-dt-selected,
1032 1032 .yui-skin-sam th.yui-dt-selected a { background-color: #446cd7 }
1033 1033 .yui-skin-sam tr.yui-dt-selected td,
1034 1034 .yui-skin-sam tr.yui-dt-selected td.yui-dt-asc,
1035 1035 .yui-skin-sam tr.yui-dt-selected td.yui-dt-desc {
1036 1036 background-color: #426fd9;
1037 1037 color: #FFF;
1038 1038 }
1039 1039 .yui-skin-sam tr.yui-dt-even td.yui-dt-selected,
1040 1040 .yui-skin-sam tr.yui-dt-odd td.yui-dt-selected {
1041 1041 background-color: #446cd7;
1042 1042 color: #FFF;
1043 1043 }
1044 1044 .yui-skin-sam .yui-dt-list th.yui-dt-selected,
1045 1045 .yui-skin-sam .yui-dt-list th.yui-dt-selected a { background-color: #446cd7 }
1046 1046 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td,
1047 1047 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-asc,
1048 1048 .yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-desc {
1049 1049 background-color: #426fd9;
1050 1050 color: #FFF;
1051 1051 }
1052 1052 .yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-selected,
1053 1053 .yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-selected {
1054 1054 background-color: #446cd7;
1055 1055 color: #FFF;
1056 1056 }
1057 1057 .yui-skin-sam .yui-dt-paginator {
1058 1058 display: block;
1059 1059 margin: 6px 0;
1060 1060 white-space: nowrap;
1061 1061 }
1062 1062 .yui-skin-sam .yui-dt-paginator .yui-dt-first,
1063 1063 .yui-skin-sam .yui-dt-paginator .yui-dt-last,
1064 1064 .yui-skin-sam .yui-dt-paginator .yui-dt-selected { padding: 2px 6px }
1065 1065 .yui-skin-sam .yui-dt-paginator a.yui-dt-first,
1066 1066 .yui-skin-sam .yui-dt-paginator a.yui-dt-last { text-decoration: none }
1067 1067 .yui-skin-sam .yui-dt-paginator .yui-dt-previous,
1068 1068 .yui-skin-sam .yui-dt-paginator .yui-dt-next { display: none }
1069 1069 .yui-skin-sam a.yui-dt-page {
1070 1070 border: 1px solid #cbcbcb;
1071 1071 padding: 2px 6px;
1072 1072 text-decoration: none;
1073 1073 background-color: #fff;
1074 1074 }
1075 1075 .yui-skin-sam .yui-dt-selected {
1076 1076 border: 1px solid #fff;
1077 1077 background-color: #fff;
1078 1078 }
1079 1079
1080 1080 #content #left {
1081 left: 0;
1082 width: 280px;
1083 position: absolute;
1081 left: 0;
1082 width: 280px;
1083 position: absolute;
1084 1084 }
1085 1085
1086 1086 #content #right {
1087 margin: 0 60px 10px 290px;
1087 margin: 0 60px 10px 290px;
1088 1088 }
1089 1089
1090 1090 #content div.box {
1091 clear: both;
1092 overflow: hidden;
1093 background: #fff;
1094 margin: 0 0 10px;
1095 padding: 0 0 10px;
1096 -webkit-border-radius: 4px 4px 4px 4px;
1097 -khtml-border-radius: 4px 4px 4px 4px;
1098 -moz-border-radius: 4px 4px 4px 4px;
1099 border-radius: 4px 4px 4px 4px;
1100 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
1091 clear: both;
1092 overflow: hidden;
1093 background: #fff;
1094 margin: 0 0 10px;
1095 padding: 0 0 10px;
1096 -webkit-border-radius: 4px 4px 4px 4px;
1097 -khtml-border-radius: 4px 4px 4px 4px;
1098 -moz-border-radius: 4px 4px 4px 4px;
1099 border-radius: 4px 4px 4px 4px;
1100 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
1101 1101 }
1102 1102
1103 1103 #content div.box-left {
1104 width: 49%;
1105 clear: none;
1106 float: left;
1107 margin: 0 0 10px;
1104 width: 49%;
1105 clear: none;
1106 float: left;
1107 margin: 0 0 10px;
1108 1108 }
1109 1109
1110 1110 #content div.box-right {
1111 width: 49%;
1112 clear: none;
1113 float: right;
1114 margin: 0 0 10px;
1111 width: 49%;
1112 clear: none;
1113 float: right;
1114 margin: 0 0 10px;
1115 1115 }
1116 1116
1117 1117 #content div.box div.title {
1118 clear: both;
1119 overflow: hidden;
1120 background-color: #003B76;
1121 background-repeat: repeat-x;
1122 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
1123 background-image: -moz-linear-gradient(top, #003b76, #00376e);
1124 background-image: -ms-linear-gradient(top, #003b76, #00376e);
1125 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
1126 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
1127 background-image: -o-linear-gradient(top, #003b76, #00376e);
1128 background-image: linear-gradient(top, #003b76, #00376e);
1129 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76', endColorstr='#00376e', GradientType=0 );
1130 margin: 0 0 20px;
1131 padding: 0;
1118 clear: both;
1119 overflow: hidden;
1120 background-color: #003B76;
1121 background-repeat: repeat-x;
1122 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
1123 background-image: -moz-linear-gradient(top, #003b76, #00376e);
1124 background-image: -ms-linear-gradient(top, #003b76, #00376e);
1125 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
1126 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
1127 background-image: -o-linear-gradient(top, #003b76, #00376e);
1128 background-image: linear-gradient(top, #003b76, #00376e);
1129 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76', endColorstr='#00376e', GradientType=0 );
1130 margin: 0 0 20px;
1131 padding: 0;
1132 1132 }
1133 1133
1134 1134 #content div.box div.title h5 {
1135 float: left;
1136 border: none;
1137 color: #fff;
1138 text-transform: uppercase;
1139 margin: 0;
1140 padding: 11px 0 11px 10px;
1135 float: left;
1136 border: none;
1137 color: #fff;
1138 text-transform: uppercase;
1139 margin: 0;
1140 padding: 11px 0 11px 10px;
1141 1141 }
1142 1142
1143 1143 #content div.box div.title .link-white{
1144 color: #FFFFFF;
1144 color: #FFFFFF;
1145 1145 }
1146 1146
1147 1147 #content div.box div.title .link-white.current{
1148 1148 color: #BFE3FF;
1149 1149 }
1150 1150
1151 1151 #content div.box div.title ul.links li {
1152 list-style: none;
1153 float: left;
1154 margin: 0;
1155 padding: 0;
1152 list-style: none;
1153 float: left;
1154 margin: 0;
1155 padding: 0;
1156 1156 }
1157 1157
1158 1158 #content div.box div.title ul.links li a {
1159 border-left: 1px solid #316293;
1160 color: #FFFFFF;
1161 display: block;
1162 float: left;
1163 font-size: 13px;
1164 font-weight: 700;
1165 height: 1%;
1166 margin: 0;
1167 padding: 11px 22px 12px;
1168 text-decoration: none;
1159 border-left: 1px solid #316293;
1160 color: #FFFFFF;
1161 display: block;
1162 float: left;
1163 font-size: 13px;
1164 font-weight: 700;
1165 height: 1%;
1166 margin: 0;
1167 padding: 11px 22px 12px;
1168 text-decoration: none;
1169 1169 }
1170 1170
1171 1171 #content div.box h1,#content div.box h2,#content div.box h3,#content div.box h4,#content div.box h5,#content div.box h6,
1172 1172 #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
1173 1173
1174 {
1175 clear: both;
1176 overflow: hidden;
1177 border-bottom: 1px solid #DDD;
1178 margin: 10px 20px;
1179 padding: 0 0 15px;
1174 {
1175 clear: both;
1176 overflow: hidden;
1177 border-bottom: 1px solid #DDD;
1178 margin: 10px 20px;
1179 padding: 0 0 15px;
1180 1180 }
1181 1181
1182 1182 #content div.box p {
1183 color: #5f5f5f;
1184 font-size: 12px;
1185 line-height: 150%;
1186 margin: 0 24px 10px;
1187 padding: 0;
1183 color: #5f5f5f;
1184 font-size: 12px;
1185 line-height: 150%;
1186 margin: 0 24px 10px;
1187 padding: 0;
1188 1188 }
1189 1189
1190 1190 #content div.box blockquote {
1191 border-left: 4px solid #DDD;
1192 color: #5f5f5f;
1193 font-size: 11px;
1194 line-height: 150%;
1195 margin: 0 34px;
1196 padding: 0 0 0 14px;
1191 border-left: 4px solid #DDD;
1192 color: #5f5f5f;
1193 font-size: 11px;
1194 line-height: 150%;
1195 margin: 0 34px;
1196 padding: 0 0 0 14px;
1197 1197 }
1198 1198
1199 1199 #content div.box blockquote p {
1200 margin: 10px 0;
1201 padding: 0;
1200 margin: 10px 0;
1201 padding: 0;
1202 1202 }
1203 1203
1204 1204 #content div.box dl {
1205 margin: 10px 0px;
1205 margin: 10px 0px;
1206 1206 }
1207 1207
1208 1208 #content div.box dt {
1209 font-size: 12px;
1210 margin: 0;
1209 font-size: 12px;
1210 margin: 0;
1211 1211 }
1212 1212
1213 1213 #content div.box dd {
1214 font-size: 12px;
1215 margin: 0;
1216 padding: 8px 0 8px 15px;
1214 font-size: 12px;
1215 margin: 0;
1216 padding: 8px 0 8px 15px;
1217 1217 }
1218 1218
1219 1219 #content div.box li {
1220 font-size: 12px;
1221 padding: 4px 0;
1220 font-size: 12px;
1221 padding: 4px 0;
1222 1222 }
1223 1223
1224 1224 #content div.box ul.disc,#content div.box ul.circle {
1225 margin: 10px 24px 10px 38px;
1225 margin: 10px 24px 10px 38px;
1226 1226 }
1227 1227
1228 1228 #content div.box ul.square {
1229 margin: 10px 24px 10px 40px;
1229 margin: 10px 24px 10px 40px;
1230 1230 }
1231 1231
1232 1232 #content div.box img.left {
1233 border: none;
1234 float: left;
1235 margin: 10px 10px 10px 0;
1233 border: none;
1234 float: left;
1235 margin: 10px 10px 10px 0;
1236 1236 }
1237 1237
1238 1238 #content div.box img.right {
1239 border: none;
1240 float: right;
1241 margin: 10px 0 10px 10px;
1239 border: none;
1240 float: right;
1241 margin: 10px 0 10px 10px;
1242 1242 }
1243 1243
1244 1244 #content div.box div.messages {
1245 clear: both;
1246 overflow: hidden;
1247 margin: 0 20px;
1248 padding: 0;
1245 clear: both;
1246 overflow: hidden;
1247 margin: 0 20px;
1248 padding: 0;
1249 1249 }
1250 1250
1251 1251 #content div.box div.message {
1252 clear: both;
1253 overflow: hidden;
1254 margin: 0;
1255 padding: 5px 0;
1252 clear: both;
1253 overflow: hidden;
1254 margin: 0;
1255 padding: 5px 0;
1256 1256 white-space: pre-wrap;
1257 1257 }
1258 1258 #content div.box div.expand {
1259 width: 110%;
1260 height:14px;
1261 font-size:10px;
1262 text-align:center;
1263 cursor: pointer;
1264 color:#666;
1265
1266 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)));
1267 background:-webkit-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1268 background:-moz-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1269 background:-o-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1270 background:-ms-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1271 background:linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1272
1273 display: none;
1259 width: 110%;
1260 height:14px;
1261 font-size:10px;
1262 text-align:center;
1263 cursor: pointer;
1264 color:#666;
1265
1266 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)));
1267 background:-webkit-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1268 background:-moz-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1269 background:-o-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1270 background:-ms-linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1271 background:linear-gradient(top,rgba(255,255,255,0),rgba(64,96,128,0.1));
1272
1273 display: none;
1274 1274 }
1275 1275 #content div.box div.expand .expandtext {
1276 background-color: #ffffff;
1277 padding: 2px;
1278 border-radius: 2px;
1276 background-color: #ffffff;
1277 padding: 2px;
1278 border-radius: 2px;
1279 1279 }
1280 1280
1281 1281 #content div.box div.message a {
1282 font-weight: 400 !important;
1282 font-weight: 400 !important;
1283 1283 }
1284 1284
1285 1285 #content div.box div.message div.image {
1286 float: left;
1287 margin: 9px 0 0 5px;
1288 padding: 6px;
1286 float: left;
1287 margin: 9px 0 0 5px;
1288 padding: 6px;
1289 1289 }
1290 1290
1291 1291 #content div.box div.message div.image img {
1292 vertical-align: middle;
1293 margin: 0;
1292 vertical-align: middle;
1293 margin: 0;
1294 1294 }
1295 1295
1296 1296 #content div.box div.message div.text {
1297 float: left;
1298 margin: 0;
1299 padding: 9px 6px;
1297 float: left;
1298 margin: 0;
1299 padding: 9px 6px;
1300 1300 }
1301 1301
1302 1302 #content div.box div.message div.dismiss a {
1303 height: 16px;
1304 width: 16px;
1305 display: block;
1306 background: url("../images/icons/cross.png") no-repeat;
1307 margin: 15px 14px 0 0;
1308 padding: 0;
1303 height: 16px;
1304 width: 16px;
1305 display: block;
1306 background: url("../images/icons/cross.png") no-repeat;
1307 margin: 15px 14px 0 0;
1308 padding: 0;
1309 1309 }
1310 1310
1311 1311 #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
1312 {
1313 border: none;
1314 margin: 0;
1315 padding: 0;
1312 {
1313 border: none;
1314 margin: 0;
1315 padding: 0;
1316 1316 }
1317 1317
1318 1318 #content div.box div.message div.text span {
1319 height: 1%;
1320 display: block;
1321 margin: 0;
1322 padding: 5px 0 0;
1319 height: 1%;
1320 display: block;
1321 margin: 0;
1322 padding: 5px 0 0;
1323 1323 }
1324 1324
1325 1325 #content div.box div.message-error {
1326 height: 1%;
1327 clear: both;
1328 overflow: hidden;
1329 background: #FBE3E4;
1330 border: 1px solid #FBC2C4;
1331 color: #860006;
1326 height: 1%;
1327 clear: both;
1328 overflow: hidden;
1329 background: #FBE3E4;
1330 border: 1px solid #FBC2C4;
1331 color: #860006;
1332 1332 }
1333 1333
1334 1334 #content div.box div.message-error h6 {
1335 color: #860006;
1335 color: #860006;
1336 1336 }
1337 1337
1338 1338 #content div.box div.message-warning {
1339 height: 1%;
1340 clear: both;
1341 overflow: hidden;
1342 background: #FFF6BF;
1343 border: 1px solid #FFD324;
1344 color: #5f5200;
1339 height: 1%;
1340 clear: both;
1341 overflow: hidden;
1342 background: #FFF6BF;
1343 border: 1px solid #FFD324;
1344 color: #5f5200;
1345 1345 }
1346 1346
1347 1347 #content div.box div.message-warning h6 {
1348 color: #5f5200;
1348 color: #5f5200;
1349 1349 }
1350 1350
1351 1351 #content div.box div.message-notice {
1352 height: 1%;
1353 clear: both;
1354 overflow: hidden;
1355 background: #8FBDE0;
1356 border: 1px solid #6BACDE;
1357 color: #003863;
1352 height: 1%;
1353 clear: both;
1354 overflow: hidden;
1355 background: #8FBDE0;
1356 border: 1px solid #6BACDE;
1357 color: #003863;
1358 1358 }
1359 1359
1360 1360 #content div.box div.message-notice h6 {
1361 color: #003863;
1361 color: #003863;
1362 1362 }
1363 1363
1364 1364 #content div.box div.message-success {
1365 height: 1%;
1366 clear: both;
1367 overflow: hidden;
1368 background: #E6EFC2;
1369 border: 1px solid #C6D880;
1370 color: #4e6100;
1365 height: 1%;
1366 clear: both;
1367 overflow: hidden;
1368 background: #E6EFC2;
1369 border: 1px solid #C6D880;
1370 color: #4e6100;
1371 1371 }
1372 1372
1373 1373 #content div.box div.message-success h6 {
1374 color: #4e6100;
1374 color: #4e6100;
1375 1375 }
1376 1376
1377 1377 #content div.box div.form div.fields div.field {
1378 height: 1%;
1379 border-bottom: 1px solid #DDD;
1380 clear: both;
1381 margin: 0;
1382 padding: 10px 0;
1378 height: 1%;
1379 border-bottom: 1px solid #DDD;
1380 clear: both;
1381 margin: 0;
1382 padding: 10px 0;
1383 1383 }
1384 1384
1385 1385 #content div.box div.form div.fields div.field-first {
1386 padding: 0 0 10px;
1386 padding: 0 0 10px;
1387 1387 }
1388 1388
1389 1389 #content div.box div.form div.fields div.field-noborder {
1390 border-bottom: 0 !important;
1390 border-bottom: 0 !important;
1391 1391 }
1392 1392
1393 1393 #content div.box div.form div.fields div.field span.error-message {
1394 height: 1%;
1395 display: inline-block;
1396 color: red;
1397 margin: 8px 0 0 4px;
1398 padding: 0;
1394 height: 1%;
1395 display: inline-block;
1396 color: red;
1397 margin: 8px 0 0 4px;
1398 padding: 0;
1399 1399 }
1400 1400
1401 1401 #content div.box div.form div.fields div.field span.success {
1402 height: 1%;
1403 display: block;
1404 color: #316309;
1405 margin: 8px 0 0;
1406 padding: 0;
1402 height: 1%;
1403 display: block;
1404 color: #316309;
1405 margin: 8px 0 0;
1406 padding: 0;
1407 1407 }
1408 1408
1409 1409 #content div.box div.form div.fields div.field div.label {
1410 left: 70px;
1411 width: 155px;
1412 position: absolute;
1413 margin: 0;
1414 padding: 5px 0 0 0px;
1410 left: 70px;
1411 width: 155px;
1412 position: absolute;
1413 margin: 0;
1414 padding: 5px 0 0 0px;
1415 1415 }
1416 1416
1417 1417 #content div.box div.form div.fields div.field div.label-summary {
1418 1418 left: 30px;
1419 1419 width: 155px;
1420 1420 position: absolute;
1421 1421 margin: 0;
1422 1422 padding: 0px 0 0 0px;
1423 1423 }
1424 1424
1425 1425 #content div.box-left div.form div.fields div.field div.label,
1426 1426 #content div.box-right div.form div.fields div.field div.label,
1427 1427 #content div.box-left div.form div.fields div.field div.label,
1428 1428 #content div.box-left div.form div.fields div.field div.label-summary,
1429 1429 #content div.box-right div.form div.fields div.field div.label-summary,
1430 1430 #content div.box-left div.form div.fields div.field div.label-summary
1431 {
1432 clear: both;
1433 overflow: hidden;
1434 left: 0;
1435 width: auto;
1436 position: relative;
1437 margin: 0;
1438 padding: 0 0 8px;
1431 {
1432 clear: both;
1433 overflow: hidden;
1434 left: 0;
1435 width: auto;
1436 position: relative;
1437 margin: 0;
1438 padding: 0 0 8px;
1439 1439 }
1440 1440
1441 1441 #content div.box div.form div.fields div.field div.label-select {
1442 padding: 5px 0 0 5px;
1442 padding: 5px 0 0 5px;
1443 1443 }
1444 1444
1445 1445 #content div.box-left div.form div.fields div.field div.label-select,
1446 1446 #content div.box-right div.form div.fields div.field div.label-select
1447 {
1448 padding: 0 0 8px;
1447 {
1448 padding: 0 0 8px;
1449 1449 }
1450 1450
1451 1451 #content div.box-left div.form div.fields div.field div.label-textarea,
1452 1452 #content div.box-right div.form div.fields div.field div.label-textarea
1453 {
1454 padding: 0 0 8px !important;
1453 {
1454 padding: 0 0 8px !important;
1455 1455 }
1456 1456
1457 1457 #content div.box div.form div.fields div.field div.label label,div.label label
1458 {
1459 color: #393939;
1460 font-weight: 700;
1458 {
1459 color: #393939;
1460 font-weight: 700;
1461 1461 }
1462 1462 #content div.box div.form div.fields div.field div.label label,div.label-summary label
1463 1463 {
1464 1464 color: #393939;
1465 1465 font-weight: 700;
1466 1466 }
1467 1467 #content div.box div.form div.fields div.field div.input {
1468 margin: 0 0 0 200px;
1468 margin: 0 0 0 200px;
1469 1469 }
1470 1470
1471 1471 #content div.box div.form div.fields div.field div.input.summary {
1472 1472 margin: 0 0 0 110px;
1473 1473 }
1474 1474 #content div.box div.form div.fields div.field div.input.summary-short {
1475 1475 margin: 0 0 0 110px;
1476 1476 }
1477 1477 #content div.box div.form div.fields div.field div.file {
1478 margin: 0 0 0 200px;
1478 margin: 0 0 0 200px;
1479 1479 }
1480 1480
1481 1481 #content div.box-left div.form div.fields div.field div.input,#content div.box-right div.form div.fields div.field div.input
1482 {
1483 margin: 0 0 0 0px;
1482 {
1483 margin: 0 0 0 0px;
1484 1484 }
1485 1485
1486 1486 #content div.box div.form div.fields div.field div.input input,
1487 1487 .reviewer_ac input {
1488 background: #FFF;
1489 border-top: 1px solid #b3b3b3;
1490 border-left: 1px solid #b3b3b3;
1491 border-right: 1px solid #eaeaea;
1492 border-bottom: 1px solid #eaeaea;
1493 color: #000;
1494 font-size: 11px;
1495 margin: 0;
1496 padding: 7px 7px 6px;
1488 background: #FFF;
1489 border-top: 1px solid #b3b3b3;
1490 border-left: 1px solid #b3b3b3;
1491 border-right: 1px solid #eaeaea;
1492 border-bottom: 1px solid #eaeaea;
1493 color: #000;
1494 font-size: 11px;
1495 margin: 0;
1496 padding: 7px 7px 6px;
1497 1497 }
1498 1498
1499 1499 #content div.box div.form div.fields div.field div.input input#clone_url,
1500 1500 #content div.box div.form div.fields div.field div.input input#clone_url_id
1501 1501 {
1502 1502 font-size: 16px;
1503 padding: 2px;
1503 padding: 2px;
1504 1504 }
1505 1505
1506 1506 #content div.box div.form div.fields div.field div.file input {
1507 background: none repeat scroll 0 0 #FFFFFF;
1508 border-color: #B3B3B3 #EAEAEA #EAEAEA #B3B3B3;
1509 border-style: solid;
1510 border-width: 1px;
1511 color: #000000;
1512 font-size: 11px;
1513 margin: 0;
1514 padding: 7px 7px 6px;
1507 background: none repeat scroll 0 0 #FFFFFF;
1508 border-color: #B3B3B3 #EAEAEA #EAEAEA #B3B3B3;
1509 border-style: solid;
1510 border-width: 1px;
1511 color: #000000;
1512 font-size: 11px;
1513 margin: 0;
1514 padding: 7px 7px 6px;
1515 1515 }
1516 1516
1517 1517 input.disabled {
1518 background-color: #F5F5F5 !important;
1518 background-color: #F5F5F5 !important;
1519 1519 }
1520 1520 #content div.box div.form div.fields div.field div.input input.small {
1521 width: 30%;
1521 width: 30%;
1522 1522 }
1523 1523
1524 1524 #content div.box div.form div.fields div.field div.input input.medium {
1525 width: 55%;
1525 width: 55%;
1526 1526 }
1527 1527
1528 1528 #content div.box div.form div.fields div.field div.input input.large {
1529 width: 85%;
1529 width: 85%;
1530 1530 }
1531 1531
1532 1532 #content div.box div.form div.fields div.field div.input input.date {
1533 width: 177px;
1533 width: 177px;
1534 1534 }
1535 1535
1536 1536 #content div.box div.form div.fields div.field div.input input.button {
1537 background: #D4D0C8;
1538 border-top: 1px solid #FFF;
1539 border-left: 1px solid #FFF;
1540 border-right: 1px solid #404040;
1541 border-bottom: 1px solid #404040;
1542 color: #000;
1543 margin: 0;
1544 padding: 4px 8px;
1537 background: #D4D0C8;
1538 border-top: 1px solid #FFF;
1539 border-left: 1px solid #FFF;
1540 border-right: 1px solid #404040;
1541 border-bottom: 1px solid #404040;
1542 color: #000;
1543 margin: 0;
1544 padding: 4px 8px;
1545 1545 }
1546 1546
1547 1547 #content div.box div.form div.fields div.field div.textarea {
1548 border-top: 1px solid #b3b3b3;
1549 border-left: 1px solid #b3b3b3;
1550 border-right: 1px solid #eaeaea;
1551 border-bottom: 1px solid #eaeaea;
1552 margin: 0 0 0 200px;
1553 padding: 10px;
1548 border-top: 1px solid #b3b3b3;
1549 border-left: 1px solid #b3b3b3;
1550 border-right: 1px solid #eaeaea;
1551 border-bottom: 1px solid #eaeaea;
1552 margin: 0 0 0 200px;
1553 padding: 10px;
1554 1554 }
1555 1555
1556 1556 #content div.box div.form div.fields div.field div.textarea-editor {
1557 border: 1px solid #ddd;
1558 padding: 0;
1557 border: 1px solid #ddd;
1558 padding: 0;
1559 1559 }
1560 1560
1561 1561 #content div.box div.form div.fields div.field div.textarea textarea {
1562 width: 100%;
1563 height: 220px;
1564 overflow: hidden;
1565 background: #FFF;
1566 color: #000;
1567 font-size: 11px;
1568 outline: none;
1569 border-width: 0;
1570 margin: 0;
1571 padding: 0;
1562 width: 100%;
1563 height: 220px;
1564 overflow: hidden;
1565 background: #FFF;
1566 color: #000;
1567 font-size: 11px;
1568 outline: none;
1569 border-width: 0;
1570 margin: 0;
1571 padding: 0;
1572 1572 }
1573 1573
1574 1574 #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
1575 {
1576 width: 100%;
1577 height: 100px;
1575 {
1576 width: 100%;
1577 height: 100px;
1578 1578 }
1579 1579
1580 1580 #content div.box div.form div.fields div.field div.textarea table {
1581 width: 100%;
1582 border: none;
1583 margin: 0;
1584 padding: 0;
1581 width: 100%;
1582 border: none;
1583 margin: 0;
1584 padding: 0;
1585 1585 }
1586 1586
1587 1587 #content div.box div.form div.fields div.field div.textarea table td {
1588 background: #DDD;
1589 border: none;
1590 padding: 0;
1588 background: #DDD;
1589 border: none;
1590 padding: 0;
1591 1591 }
1592 1592
1593 1593 #content div.box div.form div.fields div.field div.textarea table td table
1594 {
1595 width: auto;
1596 border: none;
1597 margin: 0;
1598 padding: 0;
1594 {
1595 width: auto;
1596 border: none;
1597 margin: 0;
1598 padding: 0;
1599 1599 }
1600 1600
1601 1601 #content div.box div.form div.fields div.field div.textarea table td table td
1602 {
1603 font-size: 11px;
1604 padding: 5px 5px 5px 0;
1602 {
1603 font-size: 11px;
1604 padding: 5px 5px 5px 0;
1605 1605 }
1606 1606
1607 1607 #content div.box div.form div.fields div.field input[type=text]:focus,
1608 1608 #content div.box div.form div.fields div.field input[type=password]:focus,
1609 1609 #content div.box div.form div.fields div.field input[type=file]:focus,
1610 1610 #content div.box div.form div.fields div.field textarea:focus,
1611 1611 #content div.box div.form div.fields div.field select:focus,
1612 1612 .reviewer_ac input:focus
1613 {
1614 background: #f6f6f6;
1615 border-color: #666;
1613 {
1614 background: #f6f6f6;
1615 border-color: #666;
1616 1616 }
1617 1617
1618 1618 .reviewer_ac {
1619 padding:10px
1619 padding:10px
1620 1620 }
1621 1621
1622 1622 div.form div.fields div.field div.button {
1623 margin: 0;
1624 padding: 0 0 0 8px;
1623 margin: 0;
1624 padding: 0 0 0 8px;
1625 1625 }
1626 1626 #content div.box table.noborder {
1627 border: 1px solid transparent;
1627 border: 1px solid transparent;
1628 1628 }
1629 1629
1630 1630 #content div.box table {
1631 width: 100%;
1632 border-collapse: separate;
1633 margin: 0;
1634 padding: 0;
1635 border: 1px solid #eee;
1631 width: 100%;
1632 border-collapse: separate;
1633 margin: 0;
1634 padding: 0;
1635 border: 1px solid #eee;
1636 1636 -webkit-border-radius: 4px;
1637 1637 -moz-border-radius: 4px;
1638 border-radius: 4px;
1638 border-radius: 4px;
1639 1639 }
1640 1640
1641 1641 #content div.box table th {
1642 background: #eee;
1643 border-bottom: 1px solid #ddd;
1644 padding: 5px 0px 5px 5px;
1645 text-align: left;
1642 background: #eee;
1643 border-bottom: 1px solid #ddd;
1644 padding: 5px 0px 5px 5px;
1645 text-align: left;
1646 1646 }
1647 1647
1648 1648 #content div.box table th.left {
1649 text-align: left;
1649 text-align: left;
1650 1650 }
1651 1651
1652 1652 #content div.box table th.right {
1653 text-align: right;
1653 text-align: right;
1654 1654 }
1655 1655
1656 1656 #content div.box table th.center {
1657 text-align: center;
1657 text-align: center;
1658 1658 }
1659 1659
1660 1660 #content div.box table th.selected {
1661 vertical-align: middle;
1662 padding: 0;
1661 vertical-align: middle;
1662 padding: 0;
1663 1663 }
1664 1664
1665 1665 #content div.box table td {
1666 background: #fff;
1667 border-bottom: 1px solid #cdcdcd;
1668 vertical-align: middle;
1669 padding: 5px;
1666 background: #fff;
1667 border-bottom: 1px solid #cdcdcd;
1668 vertical-align: middle;
1669 padding: 5px;
1670 1670 }
1671 1671
1672 1672 #content div.box table tr.selected td {
1673 background: #FFC;
1673 background: #FFC;
1674 1674 }
1675 1675
1676 1676 #content div.box table td.selected {
1677 width: 3%;
1678 text-align: center;
1679 vertical-align: middle;
1680 padding: 0;
1677 width: 3%;
1678 text-align: center;
1679 vertical-align: middle;
1680 padding: 0;
1681 1681 }
1682 1682
1683 1683 #content div.box table td.action {
1684 width: 45%;
1685 text-align: left;
1684 width: 45%;
1685 text-align: left;
1686 1686 }
1687 1687
1688 1688 #content div.box table td.date {
1689 width: 33%;
1690 text-align: center;
1689 width: 33%;
1690 text-align: center;
1691 1691 }
1692 1692
1693 1693 #content div.box div.action {
1694 float: right;
1695 background: #FFF;
1696 text-align: right;
1697 margin: 10px 0 0;
1698 padding: 0;
1694 float: right;
1695 background: #FFF;
1696 text-align: right;
1697 margin: 10px 0 0;
1698 padding: 0;
1699 1699 }
1700 1700
1701 1701 #content div.box div.action select {
1702 font-size: 11px;
1703 margin: 0;
1702 font-size: 11px;
1703 margin: 0;
1704 1704 }
1705 1705
1706 1706 #content div.box div.action .ui-selectmenu {
1707 margin: 0;
1708 padding: 0;
1707 margin: 0;
1708 padding: 0;
1709 1709 }
1710 1710
1711 1711 #content div.box div.pagination {
1712 height: 1%;
1713 clear: both;
1714 overflow: hidden;
1715 margin: 10px 0 0;
1716 padding: 0;
1712 height: 1%;
1713 clear: both;
1714 overflow: hidden;
1715 margin: 10px 0 0;
1716 padding: 0;
1717 1717 }
1718 1718
1719 1719 #content div.box div.pagination ul.pager {
1720 float: right;
1721 text-align: right;
1722 margin: 0;
1723 padding: 0;
1720 float: right;
1721 text-align: right;
1722 margin: 0;
1723 padding: 0;
1724 1724 }
1725 1725
1726 1726 #content div.box div.pagination ul.pager li {
1727 height: 1%;
1728 float: left;
1729 list-style: none;
1730 background: #ebebeb url("../images/pager.png") repeat-x;
1731 border-top: 1px solid #dedede;
1732 border-left: 1px solid #cfcfcf;
1733 border-right: 1px solid #c4c4c4;
1734 border-bottom: 1px solid #c4c4c4;
1735 color: #4A4A4A;
1736 font-weight: 700;
1737 margin: 0 0 0 4px;
1738 padding: 0;
1727 height: 1%;
1728 float: left;
1729 list-style: none;
1730 background: #ebebeb url("../images/pager.png") repeat-x;
1731 border-top: 1px solid #dedede;
1732 border-left: 1px solid #cfcfcf;
1733 border-right: 1px solid #c4c4c4;
1734 border-bottom: 1px solid #c4c4c4;
1735 color: #4A4A4A;
1736 font-weight: 700;
1737 margin: 0 0 0 4px;
1738 padding: 0;
1739 1739 }
1740 1740
1741 1741 #content div.box div.pagination ul.pager li.separator {
1742 padding: 6px;
1742 padding: 6px;
1743 1743 }
1744 1744
1745 1745 #content div.box div.pagination ul.pager li.current {
1746 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1747 border-top: 1px solid #ccc;
1748 border-left: 1px solid #bebebe;
1749 border-right: 1px solid #b1b1b1;
1750 border-bottom: 1px solid #afafaf;
1751 color: #515151;
1752 padding: 6px;
1746 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1747 border-top: 1px solid #ccc;
1748 border-left: 1px solid #bebebe;
1749 border-right: 1px solid #b1b1b1;
1750 border-bottom: 1px solid #afafaf;
1751 color: #515151;
1752 padding: 6px;
1753 1753 }
1754 1754
1755 1755 #content div.box div.pagination ul.pager li a {
1756 height: 1%;
1757 display: block;
1758 float: left;
1759 color: #515151;
1760 text-decoration: none;
1761 margin: 0;
1762 padding: 6px;
1756 height: 1%;
1757 display: block;
1758 float: left;
1759 color: #515151;
1760 text-decoration: none;
1761 margin: 0;
1762 padding: 6px;
1763 1763 }
1764 1764
1765 1765 #content div.box div.pagination ul.pager li a:hover,#content div.box div.pagination ul.pager li a:active
1766 {
1767 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1768 border-top: 1px solid #ccc;
1769 border-left: 1px solid #bebebe;
1770 border-right: 1px solid #b1b1b1;
1771 border-bottom: 1px solid #afafaf;
1772 margin: -1px;
1766 {
1767 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1768 border-top: 1px solid #ccc;
1769 border-left: 1px solid #bebebe;
1770 border-right: 1px solid #b1b1b1;
1771 border-bottom: 1px solid #afafaf;
1772 margin: -1px;
1773 1773 }
1774 1774
1775 1775 #content div.box div.pagination-wh {
1776 height: 1%;
1777 clear: both;
1778 overflow: hidden;
1779 text-align: right;
1780 margin: 10px 0 0;
1781 padding: 0;
1776 height: 1%;
1777 clear: both;
1778 overflow: hidden;
1779 text-align: right;
1780 margin: 10px 0 0;
1781 padding: 0;
1782 1782 }
1783 1783
1784 1784 #content div.box div.pagination-right {
1785 float: right;
1785 float: right;
1786 1786 }
1787 1787
1788 1788 #content div.box div.pagination-wh a,
1789 1789 #content div.box div.pagination-wh span.pager_dotdot,
1790 1790 #content div.box div.pagination-wh span.yui-pg-previous,
1791 1791 #content div.box div.pagination-wh span.yui-pg-last,
1792 1792 #content div.box div.pagination-wh span.yui-pg-next,
1793 1793 #content div.box div.pagination-wh span.yui-pg-first
1794 {
1795 height: 1%;
1796 float: left;
1797 background: #ebebeb url("../images/pager.png") repeat-x;
1798 border-top: 1px solid #dedede;
1799 border-left: 1px solid #cfcfcf;
1800 border-right: 1px solid #c4c4c4;
1801 border-bottom: 1px solid #c4c4c4;
1802 color: #4A4A4A;
1803 font-weight: 700;
1804 margin: 0 0 0 4px;
1805 padding: 6px;
1794 {
1795 height: 1%;
1796 float: left;
1797 background: #ebebeb url("../images/pager.png") repeat-x;
1798 border-top: 1px solid #dedede;
1799 border-left: 1px solid #cfcfcf;
1800 border-right: 1px solid #c4c4c4;
1801 border-bottom: 1px solid #c4c4c4;
1802 color: #4A4A4A;
1803 font-weight: 700;
1804 margin: 0 0 0 4px;
1805 padding: 6px;
1806 1806 }
1807 1807
1808 1808 #content div.box div.pagination-wh span.pager_curpage {
1809 height: 1%;
1810 float: left;
1811 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1812 border-top: 1px solid #ccc;
1813 border-left: 1px solid #bebebe;
1814 border-right: 1px solid #b1b1b1;
1815 border-bottom: 1px solid #afafaf;
1816 color: #515151;
1817 font-weight: 700;
1818 margin: 0 0 0 4px;
1819 padding: 6px;
1809 height: 1%;
1810 float: left;
1811 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1812 border-top: 1px solid #ccc;
1813 border-left: 1px solid #bebebe;
1814 border-right: 1px solid #b1b1b1;
1815 border-bottom: 1px solid #afafaf;
1816 color: #515151;
1817 font-weight: 700;
1818 margin: 0 0 0 4px;
1819 padding: 6px;
1820 1820 }
1821 1821
1822 1822 #content div.box div.pagination-wh a:hover,#content div.box div.pagination-wh a:active
1823 {
1824 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1825 border-top: 1px solid #ccc;
1826 border-left: 1px solid #bebebe;
1827 border-right: 1px solid #b1b1b1;
1828 border-bottom: 1px solid #afafaf;
1829 text-decoration: none;
1823 {
1824 background: #b4b4b4 url("../images/pager_selected.png") repeat-x;
1825 border-top: 1px solid #ccc;
1826 border-left: 1px solid #bebebe;
1827 border-right: 1px solid #b1b1b1;
1828 border-bottom: 1px solid #afafaf;
1829 text-decoration: none;
1830 1830 }
1831 1831
1832 1832 #content div.box div.traffic div.legend {
1833 clear: both;
1834 overflow: hidden;
1835 border-bottom: 1px solid #ddd;
1836 margin: 0 0 10px;
1837 padding: 0 0 10px;
1833 clear: both;
1834 overflow: hidden;
1835 border-bottom: 1px solid #ddd;
1836 margin: 0 0 10px;
1837 padding: 0 0 10px;
1838 1838 }
1839 1839
1840 1840 #content div.box div.traffic div.legend h6 {
1841 float: left;
1842 border: none;
1843 margin: 0;
1844 padding: 0;
1841 float: left;
1842 border: none;
1843 margin: 0;
1844 padding: 0;
1845 1845 }
1846 1846
1847 1847 #content div.box div.traffic div.legend li {
1848 list-style: none;
1849 float: left;
1850 font-size: 11px;
1851 margin: 0;
1852 padding: 0 8px 0 4px;
1848 list-style: none;
1849 float: left;
1850 font-size: 11px;
1851 margin: 0;
1852 padding: 0 8px 0 4px;
1853 1853 }
1854 1854
1855 1855 #content div.box div.traffic div.legend li.visits {
1856 border-left: 12px solid #edc240;
1856 border-left: 12px solid #edc240;
1857 1857 }
1858 1858
1859 1859 #content div.box div.traffic div.legend li.pageviews {
1860 border-left: 12px solid #afd8f8;
1860 border-left: 12px solid #afd8f8;
1861 1861 }
1862 1862
1863 1863 #content div.box div.traffic table {
1864 width: auto;
1864 width: auto;
1865 1865 }
1866 1866
1867 1867 #content div.box div.traffic table td {
1868 background: transparent;
1869 border: none;
1870 padding: 2px 3px 3px;
1868 background: transparent;
1869 border: none;
1870 padding: 2px 3px 3px;
1871 1871 }
1872 1872
1873 1873 #content div.box div.traffic table td.legendLabel {
1874 padding: 0 3px 2px;
1874 padding: 0 3px 2px;
1875 1875 }
1876 1876
1877 1877 #summary {
1878
1879 1878 }
1880 1879
1881 1880 #summary .metatag {
1882 1881 display: inline-block;
1883 1882 padding: 3px 5px;
1884 1883 margin-bottom: 3px;
1885 1884 margin-right: 1px;
1886 1885 border-radius: 5px;
1887 1886 }
1888 1887
1889 1888 #content div.box #summary p {
1890 1889 margin-bottom: -5px;
1891 1890 width: 600px;
1892 1891 white-space: pre-wrap;
1893 1892 }
1894 1893
1895 1894 #content div.box #summary p:last-child {
1896 1895 margin-bottom: 9px;
1897 1896 }
1898 1897
1899 1898 #content div.box #summary p:first-of-type {
1900 1899 margin-top: 9px;
1901 1900 }
1902 1901
1903 1902 .metatag {
1904 1903 display: inline-block;
1905 1904 margin-right: 1px;
1906 1905 -webkit-border-radius: 4px 4px 4px 4px;
1907 1906 -khtml-border-radius: 4px 4px 4px 4px;
1908 1907 -moz-border-radius: 4px 4px 4px 4px;
1909 1908 border-radius: 4px 4px 4px 4px;
1910
1909
1911 1910 border: solid 1px #9CF;
1912 1911 padding: 2px 3px 2px 3px !important;
1913 background-color: #DEF;
1912 background-color: #DEF;
1914 1913 }
1915 1914
1916 1915 .metatag[tag="dead"] {
1917 background-color: #E44;
1916 background-color: #E44;
1918 1917 }
1919 1918
1920 1919 .metatag[tag="stale"] {
1921 1920 background-color: #EA4;
1922 1921 }
1923 1922
1924 1923 .metatag[tag="featured"] {
1925 background-color: #AEA;
1926 }
1927
1928 .metatag[tag="requires"] {
1929 background-color: #9CF;
1930 }
1931
1932 .metatag[tag="recommends"] {
1933 background-color: #BDF;
1934 }
1935
1936 .metatag[tag="lang"] {
1937 background-color: #FAF474;
1924 background-color: #AEA;
1925 }
1926
1927 .metatag[tag="requires"] {
1928 background-color: #9CF;
1929 }
1930
1931 .metatag[tag="recommends"] {
1932 background-color: #BDF;
1933 }
1934
1935 .metatag[tag="lang"] {
1936 background-color: #FAF474;
1938 1937 }
1939 1938
1940 1939 .metatag[tag="license"] {
1941 1940 border: solid 1px #9CF;
1942 1941 background-color: #DEF;
1943 1942 target-new: tab !important;
1944 1943 }
1945 1944 .metatag[tag="see"] {
1946 1945 border: solid 1px #CBD;
1947 1946 background-color: #EDF;
1948 1947 }
1949 1948
1950 1949 a.metatag[tag="license"]:hover {
1951 1950 background-color: #003367;
1952 1951 color: #FFF;
1953 1952 text-decoration: none;
1954 1953 }
1955 1954
1956 1955 #summary .desc {
1957 white-space: pre;
1958 width: 100%;
1956 white-space: pre;
1957 width: 100%;
1959 1958 }
1960 1959
1961 1960 #summary .repo_name {
1962 font-size: 1.6em;
1963 font-weight: bold;
1964 vertical-align: baseline;
1965 clear: right
1961 font-size: 1.6em;
1962 font-weight: bold;
1963 vertical-align: baseline;
1964 clear: right
1966 1965 }
1967 1966
1968 1967 #footer {
1969 clear: both;
1970 overflow: hidden;
1971 text-align: right;
1972 margin: 0;
1973 padding: 0 10px 4px;
1974 margin: -10px 0 0;
1968 clear: both;
1969 overflow: hidden;
1970 text-align: right;
1971 margin: 0;
1972 padding: 0 10px 4px;
1973 margin: -10px 0 0;
1975 1974 }
1976 1975
1977 1976 #footer div#footer-inner {
1978 background-color: #003B76;
1979 background-repeat : repeat-x;
1980 background-image : -khtml-gradient( linear, left top, left bottom, from(#003B76), to(#00376E));
1981 background-image : -moz-linear-gradient(top, #003b76, #00376e);
1982 background-image : -ms-linear-gradient( top, #003b76, #00376e);
1983 background-image : -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #003b76), color-stop( 100%, #00376e));
1984 background-image : -webkit-linear-gradient( top, #003b76, #00376e));
1985 background-image : -o-linear-gradient( top, #003b76, #00376e));
1986 background-image : linear-gradient( top, #003b76, #00376e);
1987 filter :progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#003b76', endColorstr = '#00376e', GradientType = 0);
1988 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
1989 -webkit-border-radius: 4px 4px 4px 4px;
1990 -khtml-border-radius: 4px 4px 4px 4px;
1991 -moz-border-radius: 4px 4px 4px 4px;
1992 border-radius: 4px 4px 4px 4px;
1977 background-color: #003B76;
1978 background-repeat : repeat-x;
1979 background-image : -khtml-gradient( linear, left top, left bottom, from(#003B76), to(#00376E));
1980 background-image : -moz-linear-gradient(top, #003b76, #00376e);
1981 background-image : -ms-linear-gradient( top, #003b76, #00376e);
1982 background-image : -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #003b76), color-stop( 100%, #00376e));
1983 background-image : -webkit-linear-gradient( top, #003b76, #00376e));
1984 background-image : -o-linear-gradient( top, #003b76, #00376e));
1985 background-image : linear-gradient( top, #003b76, #00376e);
1986 filter :progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#003b76', endColorstr = '#00376e', GradientType = 0);
1987 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
1988 -webkit-border-radius: 4px 4px 4px 4px;
1989 -khtml-border-radius: 4px 4px 4px 4px;
1990 -moz-border-radius: 4px 4px 4px 4px;
1991 border-radius: 4px 4px 4px 4px;
1993 1992 }
1994 1993
1995 1994 #footer div#footer-inner p {
1996 padding: 15px 25px 15px 0;
1997 color: #FFF;
1998 font-weight: 700;
1995 padding: 15px 25px 15px 0;
1996 color: #FFF;
1997 font-weight: 700;
1999 1998 }
2000 1999
2001 2000 #footer div#footer-inner .footer-link {
2002 float: left;
2003 padding-left: 10px;
2001 float: left;
2002 padding-left: 10px;
2004 2003 }
2005 2004
2006 2005 #footer div#footer-inner .footer-link a,#footer div#footer-inner .footer-link-right a
2007 {
2008 color: #FFF;
2006 {
2007 color: #FFF;
2009 2008 }
2010 2009
2011 2010 #login div.title {
2012 clear: both;
2013 overflow: hidden;
2014 position: relative;
2015 background-color: #003B76;
2016 background-repeat : repeat-x;
2017 background-image : -khtml-gradient( linear, left top, left bottom, from(#003B76), to(#00376E));
2018 background-image : -moz-linear-gradient( top, #003b76, #00376e);
2019 background-image : -ms-linear-gradient( top, #003b76, #00376e);
2020 background-image : -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #003b76), color-stop( 100%, #00376e));
2021 background-image : -webkit-linear-gradient( top, #003b76, #00376e));
2022 background-image : -o-linear-gradient( top, #003b76, #00376e));
2023 background-image : linear-gradient( top, #003b76, #00376e);
2024 filter : progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#003b76', endColorstr = '#00376e', GradientType = 0);
2025 margin: 0 auto;
2026 padding: 0;
2011 clear: both;
2012 overflow: hidden;
2013 position: relative;
2014 background-color: #003B76;
2015 background-repeat : repeat-x;
2016 background-image : -khtml-gradient( linear, left top, left bottom, from(#003B76), to(#00376E));
2017 background-image : -moz-linear-gradient( top, #003b76, #00376e);
2018 background-image : -ms-linear-gradient( top, #003b76, #00376e);
2019 background-image : -webkit-gradient( linear, left top, left bottom, color-stop( 0%, #003b76), color-stop( 100%, #00376e));
2020 background-image : -webkit-linear-gradient( top, #003b76, #00376e));
2021 background-image : -o-linear-gradient( top, #003b76, #00376e));
2022 background-image : linear-gradient( top, #003b76, #00376e);
2023 filter : progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#003b76', endColorstr = '#00376e', GradientType = 0);
2024 margin: 0 auto;
2025 padding: 0;
2027 2026 }
2028 2027
2029 2028 #login div.inner {
2030 background: #FFF url("../images/login.png") no-repeat top left;
2031 border-top: none;
2032 border-bottom: none;
2033 margin: 0 auto;
2034 padding: 20px;
2029 background: #FFF url("../images/login.png") no-repeat top left;
2030 border-top: none;
2031 border-bottom: none;
2032 margin: 0 auto;
2033 padding: 20px;
2035 2034 }
2036 2035
2037 2036 #login div.form div.fields div.field div.label {
2038 width: 173px;
2039 float: left;
2040 text-align: right;
2041 margin: 2px 10px 0 0;
2042 padding: 5px 0 0 5px;
2037 width: 173px;
2038 float: left;
2039 text-align: right;
2040 margin: 2px 10px 0 0;
2041 padding: 5px 0 0 5px;
2043 2042 }
2044 2043
2045 2044 #login div.form div.fields div.field div.input input {
2046 background: #FFF;
2047 border-top: 1px solid #b3b3b3;
2048 border-left: 1px solid #b3b3b3;
2049 border-right: 1px solid #eaeaea;
2050 border-bottom: 1px solid #eaeaea;
2051 color: #000;
2052 font-size: 11px;
2053 margin: 0;
2054 padding: 7px 7px 6px;
2045 background: #FFF;
2046 border-top: 1px solid #b3b3b3;
2047 border-left: 1px solid #b3b3b3;
2048 border-right: 1px solid #eaeaea;
2049 border-bottom: 1px solid #eaeaea;
2050 color: #000;
2051 font-size: 11px;
2052 margin: 0;
2053 padding: 7px 7px 6px;
2055 2054 }
2056 2055
2057 2056 #login div.form div.fields div.buttons {
2058 clear: both;
2059 overflow: hidden;
2060 border-top: 1px solid #DDD;
2061 text-align: right;
2062 margin: 0;
2063 padding: 10px 0 0;
2057 clear: both;
2058 overflow: hidden;
2059 border-top: 1px solid #DDD;
2060 text-align: right;
2061 margin: 0;
2062 padding: 10px 0 0;
2064 2063 }
2065 2064
2066 2065 #login div.form div.links {
2067 clear: both;
2068 overflow: hidden;
2069 margin: 10px 0 0;
2070 padding: 0 0 2px;
2066 clear: both;
2067 overflow: hidden;
2068 margin: 10px 0 0;
2069 padding: 0 0 2px;
2071 2070 }
2072 2071
2073 2072 .user-menu{
2074 2073 margin: 0px !important;
2075 2074 float: left;
2076 2075 }
2077 2076
2078 2077 .user-menu .container{
2079 2078 padding:0px 4px 0px 4px;
2080 2079 margin: 0px 0px 0px 0px;
2081 2080 }
2082 2081
2083 2082 .user-menu .gravatar{
2084 2083 margin: 0px 0px 0px 0px;
2085 2084 cursor: pointer;
2086 2085 }
2087 2086 .user-menu .gravatar.enabled{
2088 background-color: #FDF784 !important;
2087 background-color: #FDF784 !important;
2089 2088 }
2090 2089 .user-menu .gravatar:hover{
2091 background-color: #FDF784 !important;
2090 background-color: #FDF784 !important;
2092 2091 }
2093 2092 #quick_login{
2094 2093 min-height: 80px;
2095 2094 padding: 4px;
2096 2095 position: absolute;
2097 2096 right: 0;
2098 2097 width: 278px;
2099 2098 background-color: #003B76;
2100 2099 background-repeat: repeat-x;
2101 2100 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
2102 2101 background-image: -moz-linear-gradient(top, #003b76, #00376e);
2103 2102 background-image: -ms-linear-gradient(top, #003b76, #00376e);
2104 2103 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
2105 2104 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
2106 2105 background-image: -o-linear-gradient(top, #003b76, #00376e);
2107 2106 background-image: linear-gradient(top, #003b76, #00376e);
2108 2107 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76', endColorstr='#00376e', GradientType=0 );
2109 2108
2110 z-index: 999;
2111 -webkit-border-radius: 0px 0px 4px 4px;
2112 -khtml-border-radius: 0px 0px 4px 4px;
2113 -moz-border-radius: 0px 0px 4px 4px;
2114 border-radius: 0px 0px 4px 4px;
2115 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
2109 z-index: 999;
2110 -webkit-border-radius: 0px 0px 4px 4px;
2111 -khtml-border-radius: 0px 0px 4px 4px;
2112 -moz-border-radius: 0px 0px 4px 4px;
2113 border-radius: 0px 0px 4px 4px;
2114 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
2116 2115 }
2117 2116 #quick_login h4{
2118 2117 color: #fff;
2119 2118 padding: 5px 0px 5px 14px;
2120 2119 }
2121 2120
2122 2121 #quick_login .password_forgoten {
2123 padding-right: 10px;
2124 padding-top: 0px;
2125 text-align: left;
2122 padding-right: 10px;
2123 padding-top: 0px;
2124 text-align: left;
2126 2125 }
2127 2126
2128 2127 #quick_login .password_forgoten a {
2129 font-size: 10px;
2130 color: #fff;
2128 font-size: 10px;
2129 color: #fff;
2131 2130 }
2132 2131
2133 2132 #quick_login .register {
2134 padding-right: 10px;
2135 padding-top: 5px;
2136 text-align: left;
2133 padding-right: 10px;
2134 padding-top: 5px;
2135 text-align: left;
2137 2136 }
2138 2137
2139 2138 #quick_login .register a {
2140 font-size: 10px;
2141 color: #fff;
2139 font-size: 10px;
2140 color: #fff;
2142 2141 }
2143 2142
2144 2143 #quick_login .submit {
2145 2144 margin: -20px 0 0 0px;
2146 2145 position: absolute;
2147 2146 right: 15px;
2148 2147 }
2149 2148
2150 2149 #quick_login .links_left{
2151 float: left;
2150 float: left;
2152 2151 }
2153 2152 #quick_login .links_right{
2154 2153 float: right;
2155 2154 }
2156 2155 #quick_login .full_name{
2157 2156 color: #FFFFFF;
2158 2157 font-weight: bold;
2159 2158 padding: 3px;
2160 2159 }
2161 2160 #quick_login .big_gravatar{
2162 padding:4px 0px 0px 6px;
2161 padding:4px 0px 0px 6px;
2163 2162 }
2164 2163 #quick_login .inbox{
2165 2164 padding:4px 0px 0px 6px;
2166 2165 color: #FFFFFF;
2167 font-weight: bold;
2166 font-weight: bold;
2168 2167 }
2169 2168 #quick_login .inbox a{
2170 color: #FFFFFF;
2169 color: #FFFFFF;
2171 2170 }
2172 2171 #quick_login .email,#quick_login .email a{
2173 2172 color: #FFFFFF;
2174 2173 padding: 3px;
2175
2174
2176 2175 }
2177 2176 #quick_login .links .logout{
2178 2177
2179 2178 }
2180 2179
2181 2180 #quick_login div.form div.fields {
2182 padding-top: 2px;
2183 padding-left: 10px;
2181 padding-top: 2px;
2182 padding-left: 10px;
2184 2183 }
2185 2184
2186 2185 #quick_login div.form div.fields div.field {
2187 padding: 5px;
2186 padding: 5px;
2188 2187 }
2189 2188
2190 2189 #quick_login div.form div.fields div.field div.label label {
2191 color: #fff;
2192 padding-bottom: 3px;
2190 color: #fff;
2191 padding-bottom: 3px;
2193 2192 }
2194 2193
2195 2194 #quick_login div.form div.fields div.field div.input input {
2196 width: 236px;
2197 background: #FFF;
2198 border-top: 1px solid #b3b3b3;
2199 border-left: 1px solid #b3b3b3;
2200 border-right: 1px solid #eaeaea;
2201 border-bottom: 1px solid #eaeaea;
2202 color: #000;
2203 font-size: 11px;
2204 margin: 0;
2205 padding: 5px 7px 4px;
2195 width: 236px;
2196 background: #FFF;
2197 border-top: 1px solid #b3b3b3;
2198 border-left: 1px solid #b3b3b3;
2199 border-right: 1px solid #eaeaea;
2200 border-bottom: 1px solid #eaeaea;
2201 color: #000;
2202 font-size: 11px;
2203 margin: 0;
2204 padding: 5px 7px 4px;
2206 2205 }
2207 2206
2208 2207 #quick_login div.form div.fields div.buttons {
2209 clear: both;
2210 overflow: hidden;
2211 text-align: right;
2212 margin: 0;
2213 padding: 5px 14px 0px 5px;
2208 clear: both;
2209 overflow: hidden;
2210 text-align: right;
2211 margin: 0;
2212 padding: 5px 14px 0px 5px;
2214 2213 }
2215 2214
2216 2215 #quick_login div.form div.links {
2217 clear: both;
2218 overflow: hidden;
2219 margin: 10px 0 0;
2220 padding: 0 0 2px;
2216 clear: both;
2217 overflow: hidden;
2218 margin: 10px 0 0;
2219 padding: 0 0 2px;
2221 2220 }
2222 2221
2223 2222 #quick_login ol.links{
2224 2223 display: block;
2225 2224 font-weight: bold;
2226 2225 list-style: none outside none;
2227 2226 text-align: right;
2228 2227 }
2229 2228 #quick_login ol.links li{
2230 2229 line-height: 27px;
2231 2230 margin: 0;
2232 2231 padding: 0;
2233 2232 color: #fff;
2234 2233 display: block;
2235 2234 float:none !important;
2236 2235 }
2237 2236
2238 2237 #quick_login ol.links li a{
2239 2238 color: #fff;
2240 2239 display: block;
2241 2240 padding: 2px;
2242 2241 }
2243 2242 #quick_login ol.links li a:HOVER{
2244 2243 background-color: inherit !important;
2245 2244 }
2246 2245
2247 2246 #register div.title {
2248 clear: both;
2249 overflow: hidden;
2250 position: relative;
2247 clear: both;
2248 overflow: hidden;
2249 position: relative;
2251 2250 background-color: #003B76;
2252 2251 background-repeat: repeat-x;
2253 2252 background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
2254 2253 background-image: -moz-linear-gradient(top, #003b76, #00376e);
2255 2254 background-image: -ms-linear-gradient(top, #003b76, #00376e);
2256 2255 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
2257 2256 background-image: -webkit-linear-gradient(top, #003b76, #00376e);
2258 2257 background-image: -o-linear-gradient(top, #003b76, #00376e);
2259 2258 background-image: linear-gradient(top, #003b76, #00376e);
2260 2259 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',
2261 2260 endColorstr='#00376e', GradientType=0 );
2262 margin: 0 auto;
2263 padding: 0;
2261 margin: 0 auto;
2262 padding: 0;
2264 2263 }
2265 2264
2266 2265 #register div.inner {
2267 background: #FFF;
2268 border-top: none;
2269 border-bottom: none;
2270 margin: 0 auto;
2271 padding: 20px;
2266 background: #FFF;
2267 border-top: none;
2268 border-bottom: none;
2269 margin: 0 auto;
2270 padding: 20px;
2272 2271 }
2273 2272
2274 2273 #register div.form div.fields div.field div.label {
2275 width: 135px;
2276 float: left;
2277 text-align: right;
2278 margin: 2px 10px 0 0;
2279 padding: 5px 0 0 5px;
2274 width: 135px;
2275 float: left;
2276 text-align: right;
2277 margin: 2px 10px 0 0;
2278 padding: 5px 0 0 5px;
2280 2279 }
2281 2280
2282 2281 #register div.form div.fields div.field div.input input {
2283 width: 300px;
2284 background: #FFF;
2285 border-top: 1px solid #b3b3b3;
2286 border-left: 1px solid #b3b3b3;
2287 border-right: 1px solid #eaeaea;
2288 border-bottom: 1px solid #eaeaea;
2289 color: #000;
2290 font-size: 11px;
2291 margin: 0;
2292 padding: 7px 7px 6px;
2282 width: 300px;
2283 background: #FFF;
2284 border-top: 1px solid #b3b3b3;
2285 border-left: 1px solid #b3b3b3;
2286 border-right: 1px solid #eaeaea;
2287 border-bottom: 1px solid #eaeaea;
2288 color: #000;
2289 font-size: 11px;
2290 margin: 0;
2291 padding: 7px 7px 6px;
2293 2292 }
2294 2293
2295 2294 #register div.form div.fields div.buttons {
2296 clear: both;
2297 overflow: hidden;
2298 border-top: 1px solid #DDD;
2299 text-align: left;
2300 margin: 0;
2301 padding: 10px 0 0 150px;
2295 clear: both;
2296 overflow: hidden;
2297 border-top: 1px solid #DDD;
2298 text-align: left;
2299 margin: 0;
2300 padding: 10px 0 0 150px;
2302 2301 }
2303 2302
2304 2303 #register div.form div.activation_msg {
2305 padding-top: 4px;
2306 padding-bottom: 4px;
2304 padding-top: 4px;
2305 padding-bottom: 4px;
2307 2306 }
2308 2307
2309 2308 #journal .journal_day {
2310 font-size: 20px;
2311 padding: 10px 0px;
2312 border-bottom: 2px solid #DDD;
2313 margin-left: 10px;
2314 margin-right: 10px;
2309 font-size: 20px;
2310 padding: 10px 0px;
2311 border-bottom: 2px solid #DDD;
2312 margin-left: 10px;
2313 margin-right: 10px;
2315 2314 }
2316 2315
2317 2316 #journal .journal_container {
2318 padding: 5px;
2319 clear: both;
2320 margin: 0px 5px 0px 10px;
2317 padding: 5px;
2318 clear: both;
2319 margin: 0px 5px 0px 10px;
2321 2320 }
2322 2321
2323 2322 #journal .journal_action_container {
2324 padding-left: 38px;
2323 padding-left: 38px;
2325 2324 }
2326 2325
2327 2326 #journal .journal_user {
2328 color: #747474;
2329 font-size: 14px;
2330 font-weight: bold;
2331 height: 30px;
2327 color: #747474;
2328 font-size: 14px;
2329 font-weight: bold;
2330 height: 30px;
2332 2331 }
2333 2332
2334 2333 #journal .journal_user.deleted {
2335 2334 color: #747474;
2336 2335 font-size: 14px;
2337 2336 font-weight: normal;
2338 2337 height: 30px;
2339 2338 font-style: italic;
2340 2339 }
2341 2340
2342 2341
2343 2342 #journal .journal_icon {
2344 clear: both;
2345 float: left;
2346 padding-right: 4px;
2347 padding-top: 3px;
2343 clear: both;
2344 float: left;
2345 padding-right: 4px;
2346 padding-top: 3px;
2348 2347 }
2349 2348
2350 2349 #journal .journal_action {
2351 padding-top: 4px;
2352 min-height: 2px;
2353 float: left
2350 padding-top: 4px;
2351 min-height: 2px;
2352 float: left
2354 2353 }
2355 2354
2356 2355 #journal .journal_action_params {
2357 clear: left;
2358 padding-left: 22px;
2356 clear: left;
2357 padding-left: 22px;
2359 2358 }
2360 2359
2361 2360 #journal .journal_repo {
2362 float: left;
2363 margin-left: 6px;
2364 padding-top: 3px;
2361 float: left;
2362 margin-left: 6px;
2363 padding-top: 3px;
2365 2364 }
2366 2365
2367 2366 #journal .date {
2368 clear: both;
2369 color: #777777;
2370 font-size: 11px;
2371 padding-left: 22px;
2367 clear: both;
2368 color: #777777;
2369 font-size: 11px;
2370 padding-left: 22px;
2372 2371 }
2373 2372
2374 2373 #journal .journal_repo .journal_repo_name {
2375 font-weight: bold;
2376 font-size: 1.1em;
2374 font-weight: bold;
2375 font-size: 1.1em;
2377 2376 }
2378 2377
2379 2378 #journal .compare_view {
2380 padding: 5px 0px 5px 0px;
2381 width: 95px;
2379 padding: 5px 0px 5px 0px;
2380 width: 95px;
2382 2381 }
2383 2382
2384 2383 .journal_highlight {
2385 font-weight: bold;
2386 padding: 0 2px;
2387 vertical-align: bottom;
2384 font-weight: bold;
2385 padding: 0 2px;
2386 vertical-align: bottom;
2388 2387 }
2389 2388
2390 2389 .trending_language_tbl,.trending_language_tbl td {
2391 border: 0 !important;
2392 margin: 0 !important;
2393 padding: 0 !important;
2390 border: 0 !important;
2391 margin: 0 !important;
2392 padding: 0 !important;
2394 2393 }
2395 2394
2396 2395 .trending_language_tbl,.trending_language_tbl tr {
2397 2396 border-spacing: 1px;
2398 2397 }
2399 2398
2400 2399 .trending_language {
2401 background-color: #003367;
2402 color: #FFF;
2403 display: block;
2404 min-width: 20px;
2405 text-decoration: none;
2406 height: 12px;
2407 margin-bottom: 0px;
2408 margin-left: 5px;
2409 white-space: pre;
2410 padding: 3px;
2400 background-color: #003367;
2401 color: #FFF;
2402 display: block;
2403 min-width: 20px;
2404 text-decoration: none;
2405 height: 12px;
2406 margin-bottom: 0px;
2407 margin-left: 5px;
2408 white-space: pre;
2409 padding: 3px;
2411 2410 }
2412 2411
2413 2412 h3.files_location {
2414 font-size: 1.8em;
2415 font-weight: 700;
2416 border-bottom: none !important;
2417 margin: 10px 0 !important;
2413 font-size: 1.8em;
2414 font-weight: 700;
2415 border-bottom: none !important;
2416 margin: 10px 0 !important;
2418 2417 }
2419 2418
2420 2419 #files_data dl dt {
2421 float: left;
2422 width: 60px;
2423 margin: 0 !important;
2424 padding: 5px;
2420 float: left;
2421 width: 60px;
2422 margin: 0 !important;
2423 padding: 5px;
2425 2424 }
2426 2425
2427 2426 #files_data dl dd {
2428 margin: 0 !important;
2429 padding: 5px !important;
2427 margin: 0 !important;
2428 padding: 5px !important;
2430 2429 }
2431 2430
2432 2431 .file_history{
2433 padding-top:10px;
2434 font-size:16px;
2432 padding-top:10px;
2433 font-size:16px;
2435 2434 }
2436 2435 .file_author{
2437 float: left;
2436 float: left;
2438 2437 }
2439 2438
2440 2439 .file_author .item{
2441 float:left;
2442 padding:5px;
2443 color: #888;
2440 float:left;
2441 padding:5px;
2442 color: #888;
2444 2443 }
2445 2444
2446 2445 .tablerow0 {
2447 background-color: #F8F8F8;
2446 background-color: #F8F8F8;
2448 2447 }
2449 2448
2450 2449 .tablerow1 {
2451 2450 background-color: #FFFFFF;
2452 2451 }
2453 2452
2454 2453 .changeset_id {
2455 font-family: monospace;
2456 color: #666666;
2454 font-family: monospace;
2455 color: #666666;
2457 2456 }
2458 2457
2459 2458 .changeset_hash {
2460 color: #000000;
2459 color: #000000;
2461 2460 }
2462 2461
2463 2462 #changeset_content {
2464 border-left: 1px solid #CCC;
2465 border-right: 1px solid #CCC;
2466 border-bottom: 1px solid #CCC;
2467 padding: 5px;
2463 border-left: 1px solid #CCC;
2464 border-right: 1px solid #CCC;
2465 border-bottom: 1px solid #CCC;
2466 padding: 5px;
2468 2467 }
2469 2468
2470 2469 #changeset_compare_view_content {
2471 border: 1px solid #CCC;
2472 padding: 5px;
2470 border: 1px solid #CCC;
2471 padding: 5px;
2473 2472 }
2474 2473
2475 2474 #changeset_content .container {
2476 min-height: 100px;
2477 font-size: 1.2em;
2478 overflow: hidden;
2475 min-height: 100px;
2476 font-size: 1.2em;
2477 overflow: hidden;
2479 2478 }
2480 2479
2481 2480 #changeset_compare_view_content .compare_view_commits {
2482 width: auto !important;
2481 width: auto !important;
2483 2482 }
2484 2483
2485 2484 #changeset_compare_view_content .compare_view_commits td {
2486 padding: 0px 0px 0px 12px !important;
2485 padding: 0px 0px 0px 12px !important;
2487 2486 }
2488 2487
2489 2488 #changeset_content .container .right {
2490 float: right;
2491 width: 20%;
2492 text-align: right;
2489 float: right;
2490 width: 20%;
2491 text-align: right;
2493 2492 }
2494 2493
2495 2494 #changeset_content .container .left .message {
2496 white-space: pre-wrap;
2495 white-space: pre-wrap;
2497 2496 }
2498 2497 #changeset_content .container .left .message a:hover {
2499 text-decoration: none;
2498 text-decoration: none;
2500 2499 }
2501 2500 .cs_files .cur_cs {
2502 margin: 10px 2px;
2503 font-weight: bold;
2501 margin: 10px 2px;
2502 font-weight: bold;
2504 2503 }
2505 2504
2506 2505 .cs_files .node {
2507 float: left;
2506 float: left;
2508 2507 }
2509 2508
2510 2509 .cs_files .changes {
2511 float: right;
2512 color:#003367;
2513
2510 float: right;
2511 color:#003367;
2514 2512 }
2515 2513
2516 2514 .cs_files .changes .added {
2517 background-color: #BBFFBB;
2518 float: left;
2519 text-align: center;
2520 font-size: 9px;
2515 background-color: #BBFFBB;
2516 float: left;
2517 text-align: center;
2518 font-size: 9px;
2521 2519 padding: 2px 0px 2px 0px;
2522 2520 }
2523 2521
2524 2522 .cs_files .changes .deleted {
2525 background-color: #FF8888;
2526 float: left;
2527 text-align: center;
2528 font-size: 9px;
2523 background-color: #FF8888;
2524 float: left;
2525 text-align: center;
2526 font-size: 9px;
2529 2527 padding: 2px 0px 2px 0px;
2530 2528 }
2531 2529 /*new binary*/
2532 2530 .cs_files .changes .bin1 {
2533 2531 background-color: #BBFFBB;
2534 2532 float: left;
2535 2533 text-align: center;
2536 2534 font-size: 9px;
2537 2535 padding: 2px 0px 2px 0px;
2538 2536 }
2539 2537
2540 2538 /*deleted binary*/
2541 2539 .cs_files .changes .bin2 {
2542 2540 background-color: #FF8888;
2543 2541 float: left;
2544 2542 text-align: center;
2545 2543 font-size: 9px;
2546 2544 padding: 2px 0px 2px 0px;
2547 2545 }
2548 2546
2549 2547 /*mod binary*/
2550 2548 .cs_files .changes .bin3 {
2551 2549 background-color: #DDDDDD;
2552 2550 float: left;
2553 2551 text-align: center;
2554 2552 font-size: 9px;
2555 2553 padding: 2px 0px 2px 0px;
2556 2554 }
2557 2555
2558 2556 /*rename file*/
2559 2557 .cs_files .changes .bin4 {
2560 2558 background-color: #6D99FF;
2561 2559 float: left;
2562 2560 text-align: center;
2563 2561 font-size: 9px;
2564 2562 padding: 2px 0px 2px 0px;
2565 2563 }
2566 2564
2567 2565
2568 2566 .cs_files .cs_added,.cs_files .cs_A {
2569 background: url("../images/icons/page_white_add.png") no-repeat scroll
2570 3px;
2571 height: 16px;
2572 padding-left: 20px;
2573 margin-top: 7px;
2574 text-align: left;
2567 background: url("../images/icons/page_white_add.png") no-repeat scroll
2568 3px;
2569 height: 16px;
2570 padding-left: 20px;
2571 margin-top: 7px;
2572 text-align: left;
2575 2573 }
2576 2574
2577 2575 .cs_files .cs_changed,.cs_files .cs_M {
2578 background: url("../images/icons/page_white_edit.png") no-repeat scroll
2579 3px;
2580 height: 16px;
2581 padding-left: 20px;
2582 margin-top: 7px;
2583 text-align: left;
2576 background: url("../images/icons/page_white_edit.png") no-repeat scroll
2577 3px;
2578 height: 16px;
2579 padding-left: 20px;
2580 margin-top: 7px;
2581 text-align: left;
2584 2582 }
2585 2583
2586 2584 .cs_files .cs_removed,.cs_files .cs_D {
2587 background: url("../images/icons/page_white_delete.png") no-repeat
2588 scroll 3px;
2589 height: 16px;
2590 padding-left: 20px;
2591 margin-top: 7px;
2592 text-align: left;
2585 background: url("../images/icons/page_white_delete.png") no-repeat
2586 scroll 3px;
2587 height: 16px;
2588 padding-left: 20px;
2589 margin-top: 7px;
2590 text-align: left;
2593 2591 }
2594 2592
2595 2593 #graph {
2596 overflow: hidden;
2594 overflow: hidden;
2597 2595 }
2598 2596
2599 2597 #graph_nodes {
2600 float: left;
2601 margin-right: 0px;
2602 margin-top: 0px;
2598 float: left;
2599 margin-right: 0px;
2600 margin-top: 0px;
2603 2601 }
2604 2602
2605 2603 #graph_content {
2606 width: 80%;
2607 float: left;
2604 width: 80%;
2605 float: left;
2608 2606 }
2609 2607
2610 2608 #graph_content .container_header {
2611 border-bottom: 1px solid #DDD;
2612 padding: 10px;
2613 height: 25px;
2609 border-bottom: 1px solid #DDD;
2610 padding: 10px;
2611 height: 25px;
2614 2612 }
2615 2613
2616 2614 #graph_content #rev_range_container {
2617 float: left;
2618 margin: 0px 0px 0px 3px;
2615 float: left;
2616 margin: 0px 0px 0px 3px;
2619 2617 }
2620 2618
2621 2619 #graph_content #rev_range_clear {
2622 2620 float: left;
2623 2621 margin: 0px 0px 0px 3px;
2624 2622 }
2625 2623
2626 2624 #graph_content .container {
2627 border-bottom: 1px solid #DDD;
2628 height: 56px;
2629 overflow: hidden;
2625 border-bottom: 1px solid #DDD;
2626 height: 56px;
2627 overflow: hidden;
2630 2628 }
2631 2629
2632 2630 #graph_content .container .right {
2633 float: right;
2634 width: 23%;
2635 text-align: right;
2631 float: right;
2632 width: 23%;
2633 text-align: right;
2636 2634 }
2637 2635
2638 2636 #graph_content .container .left {
2639 float: left;
2640 width: 25%;
2641 padding-left: 5px;
2637 float: left;
2638 width: 25%;
2639 padding-left: 5px;
2642 2640 }
2643 2641
2644 2642 #graph_content .container .mid {
2645 float: left;
2646 width: 49%;
2643 float: left;
2644 width: 49%;
2647 2645 }
2648 2646
2649 2647
2650 2648 #graph_content .container .left .date {
2651 color: #666;
2652 padding-left: 22px;
2653 font-size: 10px;
2649 color: #666;
2650 padding-left: 22px;
2651 font-size: 10px;
2654 2652 }
2655 2653
2656 2654 #graph_content .container .left .author {
2657 height: 22px;
2655 height: 22px;
2658 2656 }
2659 2657
2660 2658 #graph_content .container .left .author .user {
2661 color: #444444;
2662 float: left;
2663 margin-left: -4px;
2664 margin-top: 4px;
2659 color: #444444;
2660 float: left;
2661 margin-left: -4px;
2662 margin-top: 4px;
2665 2663 }
2666 2664
2667 2665 #graph_content .container .mid .message {
2668 white-space: pre-wrap;
2666 white-space: pre-wrap;
2669 2667 }
2670 2668
2671 2669 #graph_content .container .mid .message a:hover{
2672 text-decoration: none;
2670 text-decoration: none;
2673 2671 }
2674 2672
2675 2673 .revision-link
2676 2674 {
2677 color:#3F6F9F;
2675 color:#3F6F9F;
2678 2676 font-weight: bold !important;
2679 2677 }
2680 2678
2681 2679 .issue-tracker-link{
2682 2680 color:#3F6F9F;
2683 2681 font-weight: bold !important;
2684 2682 }
2685 2683
2686 2684 .changeset-status-container{
2687 2685 padding-right: 5px;
2688 2686 margin-top:1px;
2689 2687 float:right;
2690 2688 height:14px;
2691 2689 }
2692 2690 .code-header .changeset-status-container{
2693 float:left;
2694 padding:2px 0px 0px 2px;
2691 float:left;
2692 padding:2px 0px 0px 2px;
2695 2693 }
2696 2694 .changeset-status-container .changeset-status-lbl{
2697 color: rgb(136, 136, 136);
2695 color: rgb(136, 136, 136);
2698 2696 float: left;
2699 2697 padding: 3px 4px 0px 0px
2700 2698 }
2701 2699 .code-header .changeset-status-container .changeset-status-lbl{
2702 2700 float: left;
2703 padding: 0px 4px 0px 0px;
2701 padding: 0px 4px 0px 0px;
2704 2702 }
2705 2703 .changeset-status-container .changeset-status-ico{
2706 2704 float: left;
2707 2705 }
2708 2706 .code-header .changeset-status-container .changeset-status-ico, .container .changeset-status-ico{
2709 2707 float: left;
2710 2708 }
2711 2709 .right .comments-container{
2712 padding-right: 5px;
2713 margin-top:1px;
2714 float:right;
2715 height:14px;
2710 padding-right: 5px;
2711 margin-top:1px;
2712 float:right;
2713 height:14px;
2716 2714 }
2717 2715
2718 2716 .right .comments-cnt{
2719 2717 float: left;
2720 color: rgb(136, 136, 136);
2721 padding-right: 2px;
2718 color: rgb(136, 136, 136);
2719 padding-right: 2px;
2722 2720 }
2723 2721
2724 2722 .right .changes{
2725 clear: both;
2723 clear: both;
2726 2724 }
2727 2725
2728 2726 .right .changes .changed_total {
2729 display: block;
2730 float: right;
2731 text-align: center;
2732 min-width: 45px;
2733 cursor: pointer;
2734 color: #444444;
2735 background: #FEA;
2736 -webkit-border-radius: 0px 0px 0px 6px;
2737 -moz-border-radius: 0px 0px 0px 6px;
2738 border-radius: 0px 0px 0px 6px;
2739 padding: 1px;
2727 display: block;
2728 float: right;
2729 text-align: center;
2730 min-width: 45px;
2731 cursor: pointer;
2732 color: #444444;
2733 background: #FEA;
2734 -webkit-border-radius: 0px 0px 0px 6px;
2735 -moz-border-radius: 0px 0px 0px 6px;
2736 border-radius: 0px 0px 0px 6px;
2737 padding: 1px;
2740 2738 }
2741 2739
2742 2740 .right .changes .added,.changed,.removed {
2743 display: block;
2744 padding: 1px;
2745 color: #444444;
2746 float: right;
2747 text-align: center;
2748 min-width: 15px;
2741 display: block;
2742 padding: 1px;
2743 color: #444444;
2744 float: right;
2745 text-align: center;
2746 min-width: 15px;
2749 2747 }
2750 2748
2751 2749 .right .changes .added {
2752 background: #CFC;
2750 background: #CFC;
2753 2751 }
2754 2752
2755 2753 .right .changes .changed {
2756 background: #FEA;
2754 background: #FEA;
2757 2755 }
2758 2756
2759 2757 .right .changes .removed {
2760 background: #FAA;
2758 background: #FAA;
2761 2759 }
2762 2760
2763 2761 .right .merge {
2764 2762 padding: 1px 3px 1px 3px;
2765 2763 background-color: #fca062;
2766 2764 font-size: 10px;
2767 2765 font-weight: bold;
2768 2766 color: #ffffff;
2769 2767 text-transform: uppercase;
2770 2768 white-space: nowrap;
2771 2769 -webkit-border-radius: 3px;
2772 2770 -moz-border-radius: 3px;
2773 2771 border-radius: 3px;
2774 2772 margin-right: 2px;
2775 2773 }
2776 2774
2777 2775 .right .parent {
2778 color: #666666;
2779 clear:both;
2776 color: #666666;
2777 clear:both;
2780 2778 }
2781 2779 .right .logtags{
2782 padding: 2px 2px 2px 2px;
2780 padding: 2px 2px 2px 2px;
2783 2781 }
2784 2782 .right .logtags .branchtag,.right .logtags .tagtag,.right .logtags .booktag{
2785 2783 margin: 0px 2px;
2786 2784 }
2787 2785
2788 2786 .right .logtags .branchtag,
2789 2787 .logtags .branchtag,
2790 2788 .spantag {
2791 2789 padding: 1px 3px 1px 3px;
2792 2790 background-color: #bfbfbf;
2793 2791 font-size: 10px;
2794 2792 font-weight: bold;
2795 2793 color: #ffffff;
2796 2794 white-space: nowrap;
2797 2795 -webkit-border-radius: 3px;
2798 2796 -moz-border-radius: 3px;
2799 2797 border-radius: 3px;
2800 2798 }
2801 2799 .right .logtags .branchtag a:hover,.logtags .branchtag a{
2802 color: #ffffff;
2800 color: #ffffff;
2803 2801 }
2804 2802 .right .logtags .branchtag a:hover,.logtags .branchtag a:hover{
2805 text-decoration: none;
2806 color: #ffffff;
2803 text-decoration: none;
2804 color: #ffffff;
2807 2805 }
2808 2806 .right .logtags .tagtag,.logtags .tagtag {
2809 2807 padding: 1px 3px 1px 3px;
2810 2808 background-color: #62cffc;
2811 2809 font-size: 10px;
2812 2810 font-weight: bold;
2813 2811 color: #ffffff;
2814 2812 white-space: nowrap;
2815 2813 -webkit-border-radius: 3px;
2816 2814 -moz-border-radius: 3px;
2817 2815 border-radius: 3px;
2818 2816 }
2819 2817 .right .logtags .tagtag a:hover,.logtags .tagtag a{
2820 color: #ffffff;
2818 color: #ffffff;
2821 2819 }
2822 2820 .right .logtags .tagtag a:hover,.logtags .tagtag a:hover{
2823 2821 text-decoration: none;
2824 2822 color: #ffffff;
2825 2823 }
2826 2824 .right .logbooks .bookbook,.logbooks .bookbook,.right .logtags .bookbook,.logtags .bookbook {
2827 2825 padding: 1px 3px 1px 3px;
2828 2826 background-color: #46A546;
2829 2827 font-size: 10px;
2830 2828 font-weight: bold;
2831 2829 color: #ffffff;
2832 2830 text-transform: uppercase;
2833 2831 white-space: nowrap;
2834 2832 -webkit-border-radius: 3px;
2835 2833 -moz-border-radius: 3px;
2836 2834 border-radius: 3px;
2837 2835 }
2838 2836 .right .logbooks .bookbook,.logbooks .bookbook a,.right .logtags .bookbook,.logtags .bookbook a{
2839 color: #ffffff;
2837 color: #ffffff;
2840 2838 }
2841 2839 .right .logbooks .bookbook,.logbooks .bookbook a:hover,.right .logtags .bookbook,.logtags .bookbook a:hover{
2842 2840 text-decoration: none;
2843 2841 color: #ffffff;
2844 2842 }
2845 2843 div.browserblock {
2846 overflow: hidden;
2847 border: 1px solid #ccc;
2848 background: #f8f8f8;
2849 font-size: 100%;
2850 line-height: 125%;
2851 padding: 0;
2844 overflow: hidden;
2845 border: 1px solid #ccc;
2846 background: #f8f8f8;
2847 font-size: 100%;
2848 line-height: 125%;
2849 padding: 0;
2852 2850 -webkit-border-radius: 6px 6px 0px 0px;
2853 2851 -moz-border-radius: 6px 6px 0px 0px;
2854 border-radius: 6px 6px 0px 0px;
2852 border-radius: 6px 6px 0px 0px;
2855 2853 }
2856 2854
2857 2855 div.browserblock .browser-header {
2858 background: #FFF;
2859 padding: 10px 0px 15px 0px;
2860 width: 100%;
2856 background: #FFF;
2857 padding: 10px 0px 15px 0px;
2858 width: 100%;
2861 2859 }
2862 2860
2863 2861 div.browserblock .browser-nav {
2864 float: left
2862 float: left
2865 2863 }
2866 2864
2867 2865 div.browserblock .browser-branch {
2868 float: left;
2866 float: left;
2869 2867 }
2870 2868
2871 2869 div.browserblock .browser-branch label {
2872 color: #4A4A4A;
2873 vertical-align: text-top;
2870 color: #4A4A4A;
2871 vertical-align: text-top;
2874 2872 }
2875 2873
2876 2874 div.browserblock .browser-header span {
2877 margin-left: 5px;
2878 font-weight: 700;
2875 margin-left: 5px;
2876 font-weight: 700;
2879 2877 }
2880 2878
2881 2879 div.browserblock .browser-search {
2882 clear: both;
2883 padding: 8px 8px 0px 5px;
2884 height: 20px;
2880 clear: both;
2881 padding: 8px 8px 0px 5px;
2882 height: 20px;
2885 2883 }
2886 2884
2887 2885 div.browserblock #node_filter_box {
2888
2889 2886 }
2890 2887
2891 2888 div.browserblock .search_activate {
2892 float: left
2889 float: left
2893 2890 }
2894 2891
2895 2892 div.browserblock .add_node {
2896 float: left;
2897 padding-left: 5px;
2893 float: left;
2894 padding-left: 5px;
2898 2895 }
2899 2896
2900 2897 div.browserblock .search_activate a:hover,div.browserblock .add_node a:hover
2901 {
2902 text-decoration: none !important;
2898 {
2899 text-decoration: none !important;
2903 2900 }
2904 2901
2905 2902 div.browserblock .browser-body {
2906 background: #EEE;
2907 border-top: 1px solid #CCC;
2903 background: #EEE;
2904 border-top: 1px solid #CCC;
2908 2905 }
2909 2906
2910 2907 table.code-browser {
2911 border-collapse: collapse;
2912 width: 100%;
2908 border-collapse: collapse;
2909 width: 100%;
2913 2910 }
2914 2911
2915 2912 table.code-browser tr {
2916 margin: 3px;
2913 margin: 3px;
2917 2914 }
2918 2915
2919 2916 table.code-browser thead th {
2920 background-color: #EEE;
2921 height: 20px;
2922 font-size: 1.1em;
2923 font-weight: 700;
2924 text-align: left;
2925 padding-left: 10px;
2917 background-color: #EEE;
2918 height: 20px;
2919 font-size: 1.1em;
2920 font-weight: 700;
2921 text-align: left;
2922 padding-left: 10px;
2926 2923 }
2927 2924
2928 2925 table.code-browser tbody td {
2929 padding-left: 10px;
2930 height: 20px;
2926 padding-left: 10px;
2927 height: 20px;
2931 2928 }
2932 2929
2933 2930 table.code-browser .browser-file {
2934 background: url("../images/icons/document_16.png") no-repeat scroll 3px;
2935 height: 16px;
2936 padding-left: 20px;
2937 text-align: left;
2931 background: url("../images/icons/document_16.png") no-repeat scroll 3px;
2932 height: 16px;
2933 padding-left: 20px;
2934 text-align: left;
2938 2935 }
2939 2936 .diffblock .changeset_header {
2940 2937 height: 16px;
2941 2938 }
2942 2939 .diffblock .changeset_file {
2943 background: url("../images/icons/file.png") no-repeat scroll 3px;
2944 text-align: left;
2945 float: left;
2946 padding: 2px 0px 2px 22px;
2940 background: url("../images/icons/file.png") no-repeat scroll 3px;
2941 text-align: left;
2942 float: left;
2943 padding: 2px 0px 2px 22px;
2947 2944 }
2948 2945 .diffblock .diff-menu-wrapper{
2949 float: left;
2946 float: left;
2950 2947 }
2951 2948
2952 2949 .diffblock .diff-menu{
2953 2950 position: absolute;
2954 2951 background: none repeat scroll 0 0 #FFFFFF;
2955 2952 border-color: #003367 #666666 #666666;
2956 2953 border-right: 1px solid #666666;
2957 2954 border-style: solid solid solid;
2958 2955 border-width: 1px;
2959 2956 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
2960 2957 margin-top:5px;
2961 2958 margin-left:1px;
2962
2959
2963 2960 }
2964 2961 .diffblock .diff-actions {
2965 2962 padding: 2px 0px 0px 2px;
2966 2963 float: left;
2967 2964 }
2968 2965 .diffblock .diff-menu ul li {
2969 padding: 0px 0px 0px 0px !important;
2966 padding: 0px 0px 0px 0px !important;
2970 2967 }
2971 2968 .diffblock .diff-menu ul li a{
2972 display: block;
2973 padding: 3px 8px 3px 8px !important;
2969 display: block;
2970 padding: 3px 8px 3px 8px !important;
2974 2971 }
2975 2972 .diffblock .diff-menu ul li a:hover{
2976 2973 text-decoration: none;
2977 2974 background-color: #EEEEEE;
2978 2975 }
2979 2976 table.code-browser .browser-dir {
2980 background: url("../images/icons/folder_16.png") no-repeat scroll 3px;
2981 height: 16px;
2982 padding-left: 20px;
2983 text-align: left;
2977 background: url("../images/icons/folder_16.png") no-repeat scroll 3px;
2978 height: 16px;
2979 padding-left: 20px;
2980 text-align: left;
2984 2981 }
2985 2982
2986 2983 table.code-browser .submodule-dir {
2987 2984 background: url("../images/icons/disconnect.png") no-repeat scroll 3px;
2988 2985 height: 16px;
2989 2986 padding-left: 20px;
2990 2987 text-align: left;
2991 2988 }
2992 2989
2993 2990
2994 2991 .box .search {
2995 clear: both;
2996 overflow: hidden;
2997 margin: 0;
2998 padding: 0 20px 10px;
2992 clear: both;
2993 overflow: hidden;
2994 margin: 0;
2995 padding: 0 20px 10px;
2999 2996 }
3000 2997
3001 2998 .box .search div.search_path {
3002 background: none repeat scroll 0 0 #EEE;
3003 border: 1px solid #CCC;
3004 color: blue;
3005 margin-bottom: 10px;
3006 padding: 10px 0;
2999 background: none repeat scroll 0 0 #EEE;
3000 border: 1px solid #CCC;
3001 color: blue;
3002 margin-bottom: 10px;
3003 padding: 10px 0;
3007 3004 }
3008 3005
3009 3006 .box .search div.search_path div.link {
3010 font-weight: 700;
3011 margin-left: 25px;
3007 font-weight: 700;
3008 margin-left: 25px;
3012 3009 }
3013 3010
3014 3011 .box .search div.search_path div.link a {
3015 color: #003367;
3016 cursor: pointer;
3017 text-decoration: none;
3012 color: #003367;
3013 cursor: pointer;
3014 text-decoration: none;
3018 3015 }
3019 3016
3020 3017 #path_unlock {
3021 color: red;
3022 font-size: 1.2em;
3023 padding-left: 4px;
3018 color: red;
3019 font-size: 1.2em;
3020 padding-left: 4px;
3024 3021 }
3025 3022
3026 3023 .info_box span {
3027 margin-left: 3px;
3028 margin-right: 3px;
3024 margin-left: 3px;
3025 margin-right: 3px;
3029 3026 }
3030 3027
3031 3028 .info_box .rev {
3032 color: #003367;
3033 font-size: 1.6em;
3034 font-weight: bold;
3035 vertical-align: sub;
3029 color: #003367;
3030 font-size: 1.6em;
3031 font-weight: bold;
3032 vertical-align: sub;
3036 3033 }
3037 3034
3038 3035 .info_box input#at_rev,.info_box input#size {
3039 background: #FFF;
3040 border-top: 1px solid #b3b3b3;
3041 border-left: 1px solid #b3b3b3;
3042 border-right: 1px solid #eaeaea;
3043 border-bottom: 1px solid #eaeaea;
3044 color: #000;
3045 font-size: 12px;
3046 margin: 0;
3047 padding: 1px 5px 1px;
3036 background: #FFF;
3037 border-top: 1px solid #b3b3b3;
3038 border-left: 1px solid #b3b3b3;
3039 border-right: 1px solid #eaeaea;
3040 border-bottom: 1px solid #eaeaea;
3041 color: #000;
3042 font-size: 12px;
3043 margin: 0;
3044 padding: 1px 5px 1px;
3048 3045 }
3049 3046
3050 3047 .info_box input#view {
3051 text-align: center;
3052 padding: 4px 3px 2px 2px;
3048 text-align: center;
3049 padding: 4px 3px 2px 2px;
3053 3050 }
3054 3051
3055 3052 .yui-overlay,.yui-panel-container {
3056 visibility: hidden;
3057 position: absolute;
3058 z-index: 2;
3053 visibility: hidden;
3054 position: absolute;
3055 z-index: 2;
3059 3056 }
3060 3057
3061 3058 #tip-box {
3062 position: absolute;
3063
3064 background-color: #FFF;
3065 border: 2px solid #003367;
3066 font: 100% sans-serif;
3067 width: auto;
3068 opacity: 1px;
3069 padding: 8px;
3070
3071 white-space: pre-wrap;
3072 -webkit-border-radius: 8px 8px 8px 8px;
3073 -khtml-border-radius: 8px 8px 8px 8px;
3074 -moz-border-radius: 8px 8px 8px 8px;
3075 border-radius: 8px 8px 8px 8px;
3076 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3077 -moz-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3078 -webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3059 position: absolute;
3060
3061 background-color: #FFF;
3062 border: 2px solid #003367;
3063 font: 100% sans-serif;
3064 width: auto;
3065 opacity: 1px;
3066 padding: 8px;
3067
3068 white-space: pre-wrap;
3069 -webkit-border-radius: 8px 8px 8px 8px;
3070 -khtml-border-radius: 8px 8px 8px 8px;
3071 -moz-border-radius: 8px 8px 8px 8px;
3072 border-radius: 8px 8px 8px 8px;
3073 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3074 -moz-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3075 -webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3079 3076 }
3080 3077
3081 3078 .hl-tip-box {
3082 3079 visibility: hidden;
3083 3080 position: absolute;
3084 3081 color: #666;
3085 3082 background-color: #FFF;
3086 3083 border: 2px solid #003367;
3087 3084 font: 100% sans-serif;
3088 3085 width: auto;
3089 3086 opacity: 1px;
3090 3087 padding: 8px;
3091 3088 white-space: pre-wrap;
3092 3089 -webkit-border-radius: 8px 8px 8px 8px;
3093 3090 -khtml-border-radius: 8px 8px 8px 8px;
3094 3091 -moz-border-radius: 8px 8px 8px 8px;
3095 3092 border-radius: 8px 8px 8px 8px;
3096 3093 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
3097 3094 }
3098 3095
3099 3096
3100 3097 .mentions-container{
3101 width: 90% !important;
3098 width: 90% !important;
3102 3099 }
3103 3100 .mentions-container .yui-ac-content{
3104 width: 100% !important;
3101 width: 100% !important;
3105 3102 }
3106 3103
3107 3104 .ac {
3108 vertical-align: top;
3105 vertical-align: top;
3109 3106 }
3110 3107
3111 3108 .ac .yui-ac {
3112 position: inherit;
3113 font-size: 100%;
3109 position: inherit;
3110 font-size: 100%;
3114 3111 }
3115 3112
3116 3113 .ac .perm_ac {
3117 width: 20em;
3114 width: 20em;
3118 3115 }
3119 3116
3120 3117 .ac .yui-ac-input {
3121 width: 100%;
3118 width: 100%;
3122 3119 }
3123 3120
3124 3121 .ac .yui-ac-container {
3125 position: absolute;
3126 top: 1.6em;
3127 width: auto;
3122 position: absolute;
3123 top: 1.6em;
3124 width: auto;
3128 3125 }
3129 3126
3130 3127 .ac .yui-ac-content {
3131 position: absolute;
3132 border: 1px solid gray;
3133 background: #fff;
3134 z-index: 9050;
3135
3128 position: absolute;
3129 border: 1px solid gray;
3130 background: #fff;
3131 z-index: 9050;
3136 3132 }
3137 3133
3138 3134 .ac .yui-ac-shadow {
3139 position: absolute;
3140 width: 100%;
3141 background: #000;
3142 -moz-opacity: 0.1px;
3143 opacity: .10;
3144 filter: alpha(opacity = 10);
3145 z-index: 9049;
3146 margin: .3em;
3135 position: absolute;
3136 width: 100%;
3137 background: #000;
3138 -moz-opacity: 0.1px;
3139 opacity: .10;
3140 filter: alpha(opacity = 10);
3141 z-index: 9049;
3142 margin: .3em;
3147 3143 }
3148 3144
3149 3145 .ac .yui-ac-content ul {
3150 width: 100%;
3151 margin: 0;
3152 padding: 0;
3153 z-index: 9050;
3146 width: 100%;
3147 margin: 0;
3148 padding: 0;
3149 z-index: 9050;
3154 3150 }
3155 3151
3156 3152 .ac .yui-ac-content li {
3157 cursor: default;
3158 white-space: nowrap;
3159 margin: 0;
3160 padding: 2px 5px;
3161 height: 18px;
3162 z-index: 9050;
3163 display: block;
3164 width: auto !important;
3153 cursor: default;
3154 white-space: nowrap;
3155 margin: 0;
3156 padding: 2px 5px;
3157 height: 18px;
3158 z-index: 9050;
3159 display: block;
3160 width: auto !important;
3165 3161 }
3166 3162
3167 3163 .ac .yui-ac-content li .ac-container-wrap{
3168 3164 width: auto;
3169 3165 }
3170 3166
3171 3167 .ac .yui-ac-content li.yui-ac-prehighlight {
3172 background: #B3D4FF;
3173 z-index: 9050;
3168 background: #B3D4FF;
3169 z-index: 9050;
3174 3170 }
3175 3171
3176 3172 .ac .yui-ac-content li.yui-ac-highlight {
3177 background: #556CB5;
3178 color: #FFF;
3179 z-index: 9050;
3173 background: #556CB5;
3174 color: #FFF;
3175 z-index: 9050;
3180 3176 }
3181 3177 .ac .yui-ac-bd{
3182 z-index: 9050;
3178 z-index: 9050;
3183 3179 }
3184 3180
3185 3181 .follow {
3186 background: url("../images/icons/heart_add.png") no-repeat scroll 3px;
3187 height: 16px;
3188 width: 20px;
3189 cursor: pointer;
3190 display: block;
3191 float: right;
3192 margin-top: 2px;
3182 background: url("../images/icons/heart_add.png") no-repeat scroll 3px;
3183 height: 16px;
3184 width: 20px;
3185 cursor: pointer;
3186 display: block;
3187 float: right;
3188 margin-top: 2px;
3193 3189 }
3194 3190
3195 3191 .following {
3196 background: url("../images/icons/heart_delete.png") no-repeat scroll 3px;
3197 height: 16px;
3198 width: 20px;
3199 cursor: pointer;
3200 display: block;
3201 float: right;
3202 margin-top: 2px;
3192 background: url("../images/icons/heart_delete.png") no-repeat scroll 3px;
3193 height: 16px;
3194 width: 20px;
3195 cursor: pointer;
3196 display: block;
3197 float: right;
3198 margin-top: 2px;
3203 3199 }
3204 3200
3205 3201 .reposize {
3206 3202 background: url("../images/icons/server.png") no-repeat scroll 3px;
3207 3203 height: 16px;
3208 3204 width: 20px;
3209 3205 cursor: pointer;
3210 3206 display: block;
3211 3207 float: right;
3212 3208 margin-top: 2px;
3213 3209 }
3214 3210
3215 3211 #repo_size{
3216 display: block;
3217 margin-top: 4px;
3218 color: #666;
3219 float:right;
3212 display: block;
3213 margin-top: 4px;
3214 color: #666;
3215 float:right;
3220 3216 }
3221 3217
3222 3218 .locking_locked{
3223 3219 background: #FFF url("../images/icons/block_16.png") no-repeat scroll 3px;
3224 3220 height: 16px;
3225 3221 width: 20px;
3226 3222 cursor: pointer;
3227 3223 display: block;
3228 3224 float: right;
3229 margin-top: 2px;
3225 margin-top: 2px;
3230 3226 }
3231 3227
3232 3228 .locking_unlocked{
3233 3229 background: #FFF url("../images/icons/accept.png") no-repeat scroll 3px;
3234 3230 height: 16px;
3235 3231 width: 20px;
3236 3232 cursor: pointer;
3237 3233 display: block;
3238 3234 float: right;
3239 margin-top: 2px;
3235 margin-top: 2px;
3240 3236 }
3241 3237
3242 3238 .currently_following {
3243 padding-left: 10px;
3244 padding-bottom: 5px;
3239 padding-left: 10px;
3240 padding-bottom: 5px;
3245 3241 }
3246 3242
3247 3243 .add_icon {
3248 background: url("../images/icons/add.png") no-repeat scroll 3px;
3249 padding-left: 20px;
3250 padding-top: 0px;
3251 text-align: left;
3244 background: url("../images/icons/add.png") no-repeat scroll 3px;
3245 padding-left: 20px;
3246 padding-top: 0px;
3247 text-align: left;
3252 3248 }
3253 3249
3254 3250 .accept_icon {
3255 3251 background: url("../images/icons/accept.png") no-repeat scroll 3px;
3256 3252 padding-left: 20px;
3257 3253 padding-top: 0px;
3258 3254 text-align: left;
3259 3255 }
3260 3256
3261 3257 .edit_icon {
3262 background: url("../images/icons/application_form_edit.png") no-repeat scroll 3px;
3263 padding-left: 20px;
3264 padding-top: 0px;
3265 text-align: left;
3258 background: url("../images/icons/application_form_edit.png") no-repeat scroll 3px;
3259 padding-left: 20px;
3260 padding-top: 0px;
3261 text-align: left;
3266 3262 }
3267 3263
3268 3264 .delete_icon {
3269 background: url("../images/icons/delete.png") no-repeat scroll 3px;
3270 padding-left: 20px;
3271 padding-top: 0px;
3272 text-align: left;
3265 background: url("../images/icons/delete.png") no-repeat scroll 3px;
3266 padding-left: 20px;
3267 padding-top: 0px;
3268 text-align: left;
3273 3269 }
3274 3270
3275 3271 .refresh_icon {
3276 background: url("../images/icons/arrow_refresh.png") no-repeat scroll
3277 3px;
3278 padding-left: 20px;
3279 padding-top: 0px;
3280 text-align: left;
3272 background: url("../images/icons/arrow_refresh.png") no-repeat scroll
3273 3px;
3274 padding-left: 20px;
3275 padding-top: 0px;
3276 text-align: left;
3281 3277 }
3282 3278
3283 3279 .pull_icon {
3284 background: url("../images/icons/connect.png") no-repeat scroll 3px;
3285 padding-left: 20px;
3286 padding-top: 0px;
3287 text-align: left;
3280 background: url("../images/icons/connect.png") no-repeat scroll 3px;
3281 padding-left: 20px;
3282 padding-top: 0px;
3283 text-align: left;
3288 3284 }
3289 3285
3290 3286 .rss_icon {
3291 background: url("../images/icons/rss_16.png") no-repeat scroll 3px;
3292 padding-left: 20px;
3293 padding-top: 4px;
3294 text-align: left;
3295 font-size: 8px
3287 background: url("../images/icons/rss_16.png") no-repeat scroll 3px;
3288 padding-left: 20px;
3289 padding-top: 4px;
3290 text-align: left;
3291 font-size: 8px
3296 3292 }
3297 3293
3298 3294 .atom_icon {
3299 background: url("../images/icons/atom.png") no-repeat scroll 3px;
3300 padding-left: 20px;
3301 padding-top: 4px;
3302 text-align: left;
3303 font-size: 8px
3295 background: url("../images/icons/atom.png") no-repeat scroll 3px;
3296 padding-left: 20px;
3297 padding-top: 4px;
3298 text-align: left;
3299 font-size: 8px
3304 3300 }
3305 3301
3306 3302 .archive_icon {
3307 background: url("../images/icons/compress.png") no-repeat scroll 3px;
3308 padding-left: 20px;
3309 text-align: left;
3310 padding-top: 1px;
3303 background: url("../images/icons/compress.png") no-repeat scroll 3px;
3304 padding-left: 20px;
3305 text-align: left;
3306 padding-top: 1px;
3311 3307 }
3312 3308
3313 3309 .start_following_icon {
3314 background: url("../images/icons/heart_add.png") no-repeat scroll 3px;
3315 padding-left: 20px;
3316 text-align: left;
3317 padding-top: 0px;
3310 background: url("../images/icons/heart_add.png") no-repeat scroll 3px;
3311 padding-left: 20px;
3312 text-align: left;
3313 padding-top: 0px;
3318 3314 }
3319 3315
3320 3316 .stop_following_icon {
3321 background: url("../images/icons/heart_delete.png") no-repeat scroll 3px;
3322 padding-left: 20px;
3323 text-align: left;
3324 padding-top: 0px;
3317 background: url("../images/icons/heart_delete.png") no-repeat scroll 3px;
3318 padding-left: 20px;
3319 text-align: left;
3320 padding-top: 0px;
3325 3321 }
3326 3322
3327 3323 .action_button {
3328 border: 0;
3329 display: inline;
3324 border: 0;
3325 display: inline;
3330 3326 }
3331 3327
3332 3328 .action_button:hover {
3333 border: 0;
3334 text-decoration: underline;
3335 cursor: pointer;
3329 border: 0;
3330 text-decoration: underline;
3331 cursor: pointer;
3336 3332 }
3337 3333
3338 3334 #switch_repos {
3339 position: absolute;
3340 height: 25px;
3341 z-index: 1;
3335 position: absolute;
3336 height: 25px;
3337 z-index: 1;
3342 3338 }
3343 3339
3344 3340 #switch_repos select {
3345 min-width: 150px;
3346 max-height: 250px;
3347 z-index: 1;
3341 min-width: 150px;
3342 max-height: 250px;
3343 z-index: 1;
3348 3344 }
3349 3345
3350 3346 .breadcrumbs {
3351 border: medium none;
3352 color: #FFF;
3353 float: left;
3354 font-weight: 700;
3355 font-size: 14px;
3356 margin: 0;
3357 padding: 11px 0 11px 10px;
3347 border: medium none;
3348 color: #FFF;
3349 float: left;
3350 font-weight: 700;
3351 font-size: 14px;
3352 margin: 0;
3353 padding: 11px 0 11px 10px;
3358 3354 }
3359 3355
3360 3356 .breadcrumbs .hash {
3361 text-transform: none;
3362 color: #fff;
3357 text-transform: none;
3358 color: #fff;
3363 3359 }
3364 3360
3365 3361 .breadcrumbs a {
3366 color: #FFF;
3362 color: #FFF;
3367 3363 }
3368 3364
3369 3365 .flash_msg {
3370
3371 3366 }
3372 3367
3373 3368 .flash_msg ul {
3374
3375 3369 }
3376 3370
3377 3371 .error_red {
3378 color:red;
3372 color:red;
3379 3373 }
3380 3374
3381 3375 .error_msg {
3382 background-color: #c43c35;
3383 background-repeat: repeat-x;
3384 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35) );
3385 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3386 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3387 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35) );
3388 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3389 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3390 background-image: linear-gradient(top, #ee5f5b, #c43c35);
3391 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#c43c35', GradientType=0 );
3392 border-color: #c43c35 #c43c35 #882a25;
3376 background-color: #c43c35;
3377 background-repeat: repeat-x;
3378 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35) );
3379 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3380 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3381 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35) );
3382 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3383 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3384 background-image: linear-gradient(top, #ee5f5b, #c43c35);
3385 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#c43c35', GradientType=0 );
3386 border-color: #c43c35 #c43c35 #882a25;
3393 3387 }
3394 3388
3395 3389 .warning_msg {
3396 color: #404040 !important;
3397 background-color: #eedc94;
3398 background-repeat: repeat-x;
3399 background-image: -khtml-gradient(linear, left top, left bottom, from(#fceec1), to(#eedc94) );
3400 background-image: -moz-linear-gradient(top, #fceec1, #eedc94);
3401 background-image: -ms-linear-gradient(top, #fceec1, #eedc94);
3402 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94) );
3403 background-image: -webkit-linear-gradient(top, #fceec1, #eedc94);
3404 background-image: -o-linear-gradient(top, #fceec1, #eedc94);
3405 background-image: linear-gradient(top, #fceec1, #eedc94);
3406 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1', endColorstr='#eedc94', GradientType=0 );
3407 border-color: #eedc94 #eedc94 #e4c652;
3390 color: #404040 !important;
3391 background-color: #eedc94;
3392 background-repeat: repeat-x;
3393 background-image: -khtml-gradient(linear, left top, left bottom, from(#fceec1), to(#eedc94) );
3394 background-image: -moz-linear-gradient(top, #fceec1, #eedc94);
3395 background-image: -ms-linear-gradient(top, #fceec1, #eedc94);
3396 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94) );
3397 background-image: -webkit-linear-gradient(top, #fceec1, #eedc94);
3398 background-image: -o-linear-gradient(top, #fceec1, #eedc94);
3399 background-image: linear-gradient(top, #fceec1, #eedc94);
3400 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fceec1', endColorstr='#eedc94', GradientType=0 );
3401 border-color: #eedc94 #eedc94 #e4c652;
3408 3402 }
3409 3403
3410 3404 .success_msg {
3411 background-color: #57a957;
3412 background-repeat: repeat-x !important;
3413 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957) );
3414 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3415 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3416 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957) );
3417 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3418 background-image: -o-linear-gradient(top, #62c462, #57a957);
3419 background-image: linear-gradient(top, #62c462, #57a957);
3420 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0 );
3421 border-color: #57a957 #57a957 #3d773d;
3405 background-color: #57a957;
3406 background-repeat: repeat-x !important;
3407 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957) );
3408 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3409 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3410 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957) );
3411 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3412 background-image: -o-linear-gradient(top, #62c462, #57a957);
3413 background-image: linear-gradient(top, #62c462, #57a957);
3414 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0 );
3415 border-color: #57a957 #57a957 #3d773d;
3422 3416 }
3423 3417
3424 3418 .notice_msg {
3425 background-color: #339bb9;
3426 background-repeat: repeat-x;
3427 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9) );
3428 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3429 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3430 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9) );
3431 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3432 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3433 background-image: linear-gradient(top, #5bc0de, #339bb9);
3434 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0 );
3435 border-color: #339bb9 #339bb9 #22697d;
3419 background-color: #339bb9;
3420 background-repeat: repeat-x;
3421 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9) );
3422 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3423 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3424 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9) );
3425 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3426 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3427 background-image: linear-gradient(top, #5bc0de, #339bb9);
3428 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0 );
3429 border-color: #339bb9 #339bb9 #22697d;
3436 3430 }
3437 3431
3438 3432 .success_msg,.error_msg,.notice_msg,.warning_msg {
3439 font-size: 12px;
3440 font-weight: 700;
3441 min-height: 14px;
3442 line-height: 14px;
3443 margin-bottom: 10px;
3444 margin-top: 0;
3445 display: block;
3446 overflow: auto;
3447 padding: 6px 10px 6px 10px;
3448 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3449 position: relative;
3450 color: #FFF;
3451 border-width: 1px;
3452 border-style: solid;
3453 -webkit-border-radius: 4px;
3454 -moz-border-radius: 4px;
3455 border-radius: 4px;
3456 -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3457 -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3458 box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3433 font-size: 12px;
3434 font-weight: 700;
3435 min-height: 14px;
3436 line-height: 14px;
3437 margin-bottom: 10px;
3438 margin-top: 0;
3439 display: block;
3440 overflow: auto;
3441 padding: 6px 10px 6px 10px;
3442 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3443 position: relative;
3444 color: #FFF;
3445 border-width: 1px;
3446 border-style: solid;
3447 -webkit-border-radius: 4px;
3448 -moz-border-radius: 4px;
3449 border-radius: 4px;
3450 -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3451 -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3452 box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
3459 3453 }
3460 3454
3461 3455 #msg_close {
3462 background: transparent url("../icons/cross_grey_small.png") no-repeat scroll 0 0;
3463 cursor: pointer;
3464 height: 16px;
3465 position: absolute;
3466 right: 5px;
3467 top: 5px;
3468 width: 16px;
3456 background: transparent url("../icons/cross_grey_small.png") no-repeat scroll 0 0;
3457 cursor: pointer;
3458 height: 16px;
3459 position: absolute;
3460 right: 5px;
3461 top: 5px;
3462 width: 16px;
3469 3463 }
3470 3464 div#legend_data{
3471 padding-left:10px;
3465 padding-left:10px;
3472 3466 }
3473 3467 div#legend_container table{
3474 border: none !important;
3468 border: none !important;
3475 3469 }
3476 3470 div#legend_container table,div#legend_choices table {
3477 width: auto !important;
3471 width: auto !important;
3478 3472 }
3479 3473
3480 3474 table#permissions_manage {
3481 width: 0 !important;
3475 width: 0 !important;
3482 3476 }
3483 3477
3484 3478 table#permissions_manage span.private_repo_msg {
3485 font-size: 0.8em;
3486 opacity: 0.6px;
3479 font-size: 0.8em;
3480 opacity: 0.6px;
3487 3481 }
3488 3482
3489 3483 table#permissions_manage td.private_repo_msg {
3490 font-size: 0.8em;
3484 font-size: 0.8em;
3491 3485 }
3492 3486
3493 3487 table#permissions_manage tr#add_perm_input td {
3494 vertical-align: middle;
3488 vertical-align: middle;
3495 3489 }
3496 3490
3497 3491 div.gravatar {
3498 background-color: #FFF;
3499 float: left;
3500 margin-right: 0.7em;
3501 padding: 1px 1px 1px 1px;
3492 background-color: #FFF;
3493 float: left;
3494 margin-right: 0.7em;
3495 padding: 1px 1px 1px 1px;
3502 3496 line-height:0;
3503 -webkit-border-radius: 3px;
3504 -khtml-border-radius: 3px;
3505 -moz-border-radius: 3px;
3506 border-radius: 3px;
3497 -webkit-border-radius: 3px;
3498 -khtml-border-radius: 3px;
3499 -moz-border-radius: 3px;
3500 border-radius: 3px;
3507 3501 }
3508 3502
3509 3503 div.gravatar img {
3510 -webkit-border-radius: 2px;
3511 -khtml-border-radius: 2px;
3512 -moz-border-radius: 2px;
3513 border-radius: 2px;
3504 -webkit-border-radius: 2px;
3505 -khtml-border-radius: 2px;
3506 -moz-border-radius: 2px;
3507 border-radius: 2px;
3514 3508 }
3515 3509
3516 3510 #header,#content,#footer {
3517 min-width: 978px;
3511 min-width: 978px;
3518 3512 }
3519 3513
3520 3514 #content {
3521 clear: both;
3522 overflow: hidden;
3523 padding: 54px 10px 14px 10px;
3515 clear: both;
3516 overflow: hidden;
3517 padding: 54px 10px 14px 10px;
3524 3518 }
3525 3519
3526 3520 #content div.box div.title div.search {
3527
3528 border-left: 1px solid #316293;
3521 border-left: 1px solid #316293;
3529 3522 }
3530 3523
3531 3524 #content div.box div.title div.search div.input input {
3532 border: 1px solid #316293;
3525 border: 1px solid #316293;
3533 3526 }
3534 3527
3535 3528 .ui-btn{
3536 3529 color: #515151;
3537 3530 background-color: #DADADA;
3538 3531 background-repeat: repeat-x;
3539 3532 background-image: -khtml-gradient(linear, left top, left bottom, from(#F4F4F4),to(#DADADA) );
3540 3533 background-image: -moz-linear-gradient(top, #F4F4F4, #DADADA);
3541 3534 background-image: -ms-linear-gradient(top, #F4F4F4, #DADADA);
3542 3535 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #F4F4F4),color-stop(100%, #DADADA) );
3543 3536 background-image: -webkit-linear-gradient(top, #F4F4F4, #DADADA) );
3544 3537 background-image: -o-linear-gradient(top, #F4F4F4, #DADADA) );
3545 3538 background-image: linear-gradient(top, #F4F4F4, #DADADA);
3546 3539 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F4F4F4', endColorstr='#DADADA', GradientType=0);
3547
3540
3548 3541 border-top: 1px solid #DDD;
3549 3542 border-left: 1px solid #c6c6c6;
3550 3543 border-right: 1px solid #DDD;
3551 3544 border-bottom: 1px solid #c6c6c6;
3552 3545 color: #515151;
3553 3546 outline: none;
3554 3547 margin: 0px 3px 3px 0px;
3555 3548 -webkit-border-radius: 4px 4px 4px 4px !important;
3556 3549 -khtml-border-radius: 4px 4px 4px 4px !important;
3557 3550 -moz-border-radius: 4px 4px 4px 4px !important;
3558 3551 border-radius: 4px 4px 4px 4px !important;
3559 3552 cursor: pointer !important;
3560 padding: 3px 3px 3px 3px;
3561 background-position: 0 -15px;
3553 padding: 3px 3px 3px 3px;
3554 background-position: 0 -15px;
3562 3555
3563 3556 }
3564 3557
3565 3558 .ui-btn.disabled{
3566 color: #999;
3559 color: #999;
3567 3560 }
3568 3561
3569 3562 .ui-btn.xsmall{
3570 3563 padding: 1px 2px 1px 1px;
3571 3564 }
3572 3565
3573 3566 .ui-btn.large{
3574 padding: 6px 12px;
3567 padding: 6px 12px;
3575 3568 }
3576 3569
3577 3570 .ui-btn.clone{
3578 padding: 5px 2px 6px 1px;
3579 margin: 0px -4px 3px 0px;
3571 padding: 5px 2px 6px 1px;
3572 margin: 0px -4px 3px 0px;
3580 3573 -webkit-border-radius: 4px 0px 0px 4px !important;
3581 3574 -khtml-border-radius: 4px 0px 0px 4px !important;
3582 3575 -moz-border-radius: 4px 0px 0px 4px !important;
3583 3576 border-radius: 4px 0px 0px 4px !important;
3584 3577 width: 100px;
3585 3578 text-align: center;
3586 3579 float: left;
3587 3580 position: absolute;
3588 3581 }
3589 3582 .ui-btn:focus {
3590 3583 outline: none;
3591 3584 }
3592 3585 .ui-btn:hover{
3593 3586 background-position: 0 -15px;
3594 3587 text-decoration: none;
3595 3588 color: #515151;
3596 3589 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), 0 0 3px #FFFFFF !important;
3597 3590 }
3598 3591
3599 3592 .ui-btn.disabled:hover{
3600 3593 background-position:none;
3601 3594 color: #999;
3602 3595 text-decoration: none;
3603 3596 box-shadow: none !important;
3604 3597 }
3605 3598
3606 3599 .ui-btn.red{
3607 3600 color:#fff;
3608 3601 background-color: #c43c35;
3609 3602 background-repeat: repeat-x;
3610 3603 background-image: -khtml-gradient(linear, left top, left bottom, from(#ee5f5b), to(#c43c35));
3611 3604 background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
3612 3605 background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
3613 3606 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ee5f5b), color-stop(100%, #c43c35));
3614 3607 background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
3615 3608 background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
3616 3609 background-image: linear-gradient(top, #ee5f5b, #c43c35);
3617 3610 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);
3618 3611 border-color: #c43c35 #c43c35 #882a25;
3619 3612 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3620 3613 }
3621 3614
3622 3615
3623 3616 .ui-btn.blue{
3624 3617 color:#fff;
3625 3618 background-color: #339bb9;
3626 3619 background-repeat: repeat-x;
3627 3620 background-image: -khtml-gradient(linear, left top, left bottom, from(#5bc0de), to(#339bb9));
3628 3621 background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
3629 3622 background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
3630 3623 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5bc0de), color-stop(100%, #339bb9));
3631 3624 background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
3632 3625 background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
3633 3626 background-image: linear-gradient(top, #5bc0de, #339bb9);
3634 3627 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);
3635 3628 border-color: #339bb9 #339bb9 #22697d;
3636 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3629 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3637 3630 }
3638 3631
3639 3632 .ui-btn.green{
3640 3633 background-color: #57a957;
3641 3634 background-repeat: repeat-x;
3642 3635 background-image: -khtml-gradient(linear, left top, left bottom, from(#62c462), to(#57a957));
3643 3636 background-image: -moz-linear-gradient(top, #62c462, #57a957);
3644 3637 background-image: -ms-linear-gradient(top, #62c462, #57a957);
3645 3638 background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #62c462), color-stop(100%, #57a957));
3646 3639 background-image: -webkit-linear-gradient(top, #62c462, #57a957);
3647 3640 background-image: -o-linear-gradient(top, #62c462, #57a957);
3648 3641 background-image: linear-gradient(top, #62c462, #57a957);
3649 3642 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);
3650 3643 border-color: #57a957 #57a957 #3d773d;
3651 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3644 border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
3652 3645 }
3653 3646
3654 3647 .ui-btn.blue.hidden{
3655 display: none;
3648 display: none;
3656 3649 }
3657 3650
3658 3651 .ui-btn.active{
3659 3652 font-weight: bold;
3660 3653 }
3661 3654
3662 3655 ins,div.options a:hover {
3663 text-decoration: none;
3656 text-decoration: none;
3664 3657 }
3665 3658
3666 3659 img,
3667 3660 #header #header-inner #quick li a:hover span.normal,
3668 3661 #header #header-inner #quick li ul li.last,
3669 3662 #content div.box div.form div.fields div.field div.textarea table td table td a,
3670 3663 #clone_url,
3671 3664 #clone_url_id
3672 3665 {
3673 border: none;
3666 border: none;
3674 3667 }
3675 3668
3676 3669 img.icon,.right .merge img {
3677 vertical-align: bottom;
3670 vertical-align: bottom;
3678 3671 }
3679 3672
3680 3673 #header ul#logged-user,#content div.box div.title ul.links,
3681 3674 #content div.box div.message div.dismiss,
3682 3675 #content div.box div.traffic div.legend ul
3683 {
3684 float: right;
3685 margin: 0;
3686 padding: 0;
3676 {
3677 float: right;
3678 margin: 0;
3679 padding: 0;
3687 3680 }
3688 3681
3689 3682 #header #header-inner #home,#header #header-inner #logo,
3690 3683 #content div.box ul.left,#content div.box ol.left,
3691 3684 #content div.box div.pagination-left,div#commit_history,
3692 3685 div#legend_data,div#legend_container,div#legend_choices
3693 {
3694 float: left;
3686 {
3687 float: left;
3695 3688 }
3696 3689
3697 3690 #header #header-inner #quick li #quick_login,
3698 3691 #header #header-inner #quick li:hover ul ul,
3699 3692 #header #header-inner #quick li:hover ul ul ul,
3700 3693 #header #header-inner #quick li:hover ul ul ul ul,
3701 3694 #content #left #menu ul.closed,#content #left #menu li ul.collapsed,.yui-tt-shadow
3702 {
3703 display: none;
3695 {
3696 display: none;
3704 3697 }
3705 3698
3706 3699 #header #header-inner #quick li:hover #quick_login,
3707 3700 #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
3708 {
3709 display: block;
3701 {
3702 display: block;
3710 3703 }
3711 3704
3712 3705 #content div.graph {
3713 padding: 0 10px 10px;
3706 padding: 0 10px 10px;
3714 3707 }
3715 3708
3716 3709 #content div.box div.title ul.links li a:hover,#content div.box div.title ul.links li.ui-tabs-selected a
3717 {
3718 color: #bfe3ff;
3710 {
3711 color: #bfe3ff;
3719 3712 }
3720 3713
3721 3714 #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
3722 {
3723 margin: 10px 24px 10px 44px;
3715 {
3716 margin: 10px 24px 10px 44px;
3724 3717 }
3725 3718
3726 3719 #content div.box div.form,#content div.box div.table,#content div.box div.traffic
3727 {
3728 clear: both;
3729 overflow: hidden;
3730 margin: 0;
3731 padding: 0 20px 10px;
3720 {
3721 clear: both;
3722 overflow: hidden;
3723 margin: 0;
3724 padding: 0 20px 10px;
3732 3725 }
3733 3726
3734 3727 #content div.box div.form div.fields,#login div.form,#login div.form div.fields,#register div.form,#register div.form div.fields
3735 {
3736 clear: both;
3737 overflow: hidden;
3738 margin: 0;
3739 padding: 0;
3728 {
3729 clear: both;
3730 overflow: hidden;
3731 margin: 0;
3732 padding: 0;
3740 3733 }
3741 3734
3742 3735 #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
3743 {
3744 height: 1%;
3745 display: block;
3746 color: #363636;
3747 margin: 0;
3748 padding: 2px 0 0;
3736 {
3737 height: 1%;
3738 display: block;
3739 color: #363636;
3740 margin: 0;
3741 padding: 2px 0 0;
3749 3742 }
3750 3743
3751 3744 #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
3752 {
3753 background: #FBE3E4;
3754 border-top: 1px solid #e1b2b3;
3755 border-left: 1px solid #e1b2b3;
3756 border-right: 1px solid #FBC2C4;
3757 border-bottom: 1px solid #FBC2C4;
3745 {
3746 background: #FBE3E4;
3747 border-top: 1px solid #e1b2b3;
3748 border-left: 1px solid #e1b2b3;
3749 border-right: 1px solid #FBC2C4;
3750 border-bottom: 1px solid #FBC2C4;
3758 3751 }
3759 3752
3760 3753 #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
3761 {
3762 background: #E6EFC2;
3763 border-top: 1px solid #cebb98;
3764 border-left: 1px solid #cebb98;
3765 border-right: 1px solid #c6d880;
3766 border-bottom: 1px solid #c6d880;
3754 {
3755 background: #E6EFC2;
3756 border-top: 1px solid #cebb98;
3757 border-left: 1px solid #cebb98;
3758 border-right: 1px solid #c6d880;
3759 border-bottom: 1px solid #c6d880;
3767 3760 }
3768 3761
3769 3762 #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
3770 {
3771 margin: 0;
3763 {
3764 margin: 0;
3772 3765 }
3773 3766
3774 3767 #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
3775 {
3776 margin: 0 0 0 0px !important;
3777 padding: 0;
3768 {
3769 margin: 0 0 0 0px !important;
3770 padding: 0;
3778 3771 }
3779 3772
3780 3773 #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
3781 {
3782 margin: 0 0 0 200px;
3783 padding: 0;
3774 {
3775 margin: 0 0 0 200px;
3776 padding: 0;
3784 3777 }
3785 3778
3786 3779 #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
3787 {
3788 color: #000;
3789 text-decoration: none;
3780 {
3781 color: #000;
3782 text-decoration: none;
3790 3783 }
3791 3784
3792 3785 #content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus,#content div.box div.action a.ui-selectmenu-focus
3793 {
3794 border: 1px solid #666;
3786 {
3787 border: 1px solid #666;
3795 3788 }
3796 3789
3797 3790 #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
3798 {
3799 clear: both;
3800 overflow: hidden;
3801 margin: 0;
3802 padding: 8px 0 2px;
3791 {
3792 clear: both;
3793 overflow: hidden;
3794 margin: 0;
3795 padding: 8px 0 2px;
3803 3796 }
3804 3797
3805 3798 #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
3806 {
3807 float: left;
3808 margin: 0;
3799 {
3800 float: left;
3801 margin: 0;
3809 3802 }
3810 3803
3811 3804 #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
3812 {
3813 height: 1%;
3814 display: block;
3815 float: left;
3816 margin: 2px 0 0 4px;
3805 {
3806 height: 1%;
3807 display: block;
3808 float: left;
3809 margin: 2px 0 0 4px;
3817 3810 }
3818 3811
3819 3812 div.form div.fields div.field div.button input,
3820 3813 #content div.box div.form div.fields div.buttons input
3821 3814 div.form div.fields div.buttons input,
3822 3815 #content div.box div.action div.button input {
3823 /*color: #000;*/
3816 /*color: #000;*/
3824 3817 font-size: 11px;
3825 3818 font-weight: 700;
3826 3819 margin: 0;
3827 3820 }
3828 3821
3829 3822 input.ui-button {
3830 background: #e5e3e3 url("../images/button.png") repeat-x;
3831 border-top: 1px solid #DDD;
3832 border-left: 1px solid #c6c6c6;
3833 border-right: 1px solid #DDD;
3834 border-bottom: 1px solid #c6c6c6;
3835 color: #515151 !important;
3836 outline: none;
3837 margin: 0;
3838 padding: 6px 12px;
3839 -webkit-border-radius: 4px 4px 4px 4px;
3840 -khtml-border-radius: 4px 4px 4px 4px;
3841 -moz-border-radius: 4px 4px 4px 4px;
3842 border-radius: 4px 4px 4px 4px;
3843 box-shadow: 0 1px 0 #ececec;
3844 cursor: pointer;
3823 background: #e5e3e3 url("../images/button.png") repeat-x;
3824 border-top: 1px solid #DDD;
3825 border-left: 1px solid #c6c6c6;
3826 border-right: 1px solid #DDD;
3827 border-bottom: 1px solid #c6c6c6;
3828 color: #515151 !important;
3829 outline: none;
3830 margin: 0;
3831 padding: 6px 12px;
3832 -webkit-border-radius: 4px 4px 4px 4px;
3833 -khtml-border-radius: 4px 4px 4px 4px;
3834 -moz-border-radius: 4px 4px 4px 4px;
3835 border-radius: 4px 4px 4px 4px;
3836 box-shadow: 0 1px 0 #ececec;
3837 cursor: pointer;
3845 3838 }
3846 3839
3847 3840 input.ui-button:hover {
3848 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
3849 border-top: 1px solid #ccc;
3850 border-left: 1px solid #bebebe;
3851 border-right: 1px solid #b1b1b1;
3852 border-bottom: 1px solid #afafaf;
3841 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
3842 border-top: 1px solid #ccc;
3843 border-left: 1px solid #bebebe;
3844 border-right: 1px solid #b1b1b1;
3845 border-bottom: 1px solid #afafaf;
3853 3846 }
3854 3847
3855 3848 div.form div.fields div.field div.highlight,#content div.box div.form div.fields div.buttons div.highlight
3856 {
3857 display: inline;
3849 {
3850 display: inline;
3858 3851 }
3859 3852
3860 3853 #content div.box div.form div.fields div.buttons,div.form div.fields div.buttons
3861 {
3862 margin: 10px 0 0 200px;
3863 padding: 0;
3854 {
3855 margin: 10px 0 0 200px;
3856 padding: 0;
3864 3857 }
3865 3858
3866 3859 #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
3867 {
3868 margin: 10px 0 0;
3860 {
3861 margin: 10px 0 0;
3869 3862 }
3870 3863
3871 3864 #content div.box table td.user,#content div.box table td.address {
3872 width: 10%;
3873 text-align: center;
3865 width: 10%;
3866 text-align: center;
3874 3867 }
3875 3868
3876 3869 #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
3877 {
3878 text-align: right;
3879 margin: 6px 0 0;
3880 padding: 0;
3870 {
3871 text-align: right;
3872 margin: 6px 0 0;
3873 padding: 0;
3881 3874 }
3882 3875
3883 3876 #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
3884 {
3885 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
3886 border-top: 1px solid #ccc;
3887 border-left: 1px solid #bebebe;
3888 border-right: 1px solid #b1b1b1;
3889 border-bottom: 1px solid #afafaf;
3890 color: #515151;
3891 margin: 0;
3892 padding: 6px 12px;
3877 {
3878 background: #b4b4b4 url("../images/button_selected.png") repeat-x;
3879 border-top: 1px solid #ccc;
3880 border-left: 1px solid #bebebe;
3881 border-right: 1px solid #b1b1b1;
3882 border-bottom: 1px solid #afafaf;
3883 color: #515151;
3884 margin: 0;
3885 padding: 6px 12px;
3893 3886 }
3894 3887
3895 3888 #content div.box div.pagination div.results,#content div.box div.pagination-wh div.results
3896 {
3897 text-align: left;
3898 float: left;
3899 margin: 0;
3900 padding: 0;
3889 {
3890 text-align: left;
3891 float: left;
3892 margin: 0;
3893 padding: 0;
3901 3894 }
3902 3895
3903 3896 #content div.box div.pagination div.results span,#content div.box div.pagination-wh div.results span
3904 {
3905 height: 1%;
3906 display: block;
3907 float: left;
3908 background: #ebebeb url("../images/pager.png") repeat-x;
3909 border-top: 1px solid #dedede;
3910 border-left: 1px solid #cfcfcf;
3911 border-right: 1px solid #c4c4c4;
3912 border-bottom: 1px solid #c4c4c4;
3913 color: #4A4A4A;
3914 font-weight: 700;
3915 margin: 0;
3916 padding: 6px 8px;
3897 {
3898 height: 1%;
3899 display: block;
3900 float: left;
3901 background: #ebebeb url("../images/pager.png") repeat-x;
3902 border-top: 1px solid #dedede;
3903 border-left: 1px solid #cfcfcf;
3904 border-right: 1px solid #c4c4c4;
3905 border-bottom: 1px solid #c4c4c4;
3906 color: #4A4A4A;
3907 font-weight: 700;
3908 margin: 0;
3909 padding: 6px 8px;
3917 3910 }
3918 3911
3919 3912 #content div.box div.pagination ul.pager li.disabled,#content div.box div.pagination-wh a.disabled
3920 {
3921 color: #B4B4B4;
3922 padding: 6px;
3913 {
3914 color: #B4B4B4;
3915 padding: 6px;
3923 3916 }
3924 3917
3925 3918 #login,#register {
3926 width: 520px;
3927 margin: 10% auto 0;
3928 padding: 0;
3919 width: 520px;
3920 margin: 10% auto 0;
3921 padding: 0;
3929 3922 }
3930 3923
3931 3924 #login div.color,#register div.color {
3932 clear: both;
3933 overflow: hidden;
3934 background: #FFF;
3935 margin: 10px auto 0;
3936 padding: 3px 3px 3px 0;
3925 clear: both;
3926 overflow: hidden;
3927 background: #FFF;
3928 margin: 10px auto 0;
3929 padding: 3px 3px 3px 0;
3937 3930 }
3938 3931
3939 3932 #login div.color a,#register div.color a {
3940 width: 20px;
3941 height: 20px;
3942 display: block;
3943 float: left;
3944 margin: 0 0 0 3px;
3945 padding: 0;
3933 width: 20px;
3934 height: 20px;
3935 display: block;
3936 float: left;
3937 margin: 0 0 0 3px;
3938 padding: 0;
3946 3939 }
3947 3940
3948 3941 #login div.title h5,#register div.title h5 {
3949 color: #fff;
3950 margin: 10px;
3951 padding: 0;
3942 color: #fff;
3943 margin: 10px;
3944 padding: 0;
3952 3945 }
3953 3946
3954 3947 #login div.form div.fields div.field,#register div.form div.fields div.field
3955 {
3956 clear: both;
3957 overflow: hidden;
3958 margin: 0;
3959 padding: 0 0 10px;
3948 {
3949 clear: both;
3950 overflow: hidden;
3951 margin: 0;
3952 padding: 0 0 10px;
3960 3953 }
3961 3954
3962 3955 #login div.form div.fields div.field span.error-message,#register div.form div.fields div.field span.error-message
3963 {
3964 height: 1%;
3965 display: block;
3966 color: red;
3967 margin: 8px 0 0;
3968 padding: 0;
3969 max-width: 320px;
3956 {
3957 height: 1%;
3958 display: block;
3959 color: red;
3960 margin: 8px 0 0;
3961 padding: 0;
3962 max-width: 320px;
3970 3963 }
3971 3964
3972 3965 #login div.form div.fields div.field div.label label,#register div.form div.fields div.field div.label label
3973 {
3974 color: #000;
3975 font-weight: 700;
3966 {
3967 color: #000;
3968 font-weight: 700;
3976 3969 }
3977 3970
3978 3971 #login div.form div.fields div.field div.input,#register div.form div.fields div.field div.input
3979 {
3980 float: left;
3981 margin: 0;
3982 padding: 0;
3972 {
3973 float: left;
3974 margin: 0;
3975 padding: 0;
3983 3976 }
3984 3977
3985 3978 #login div.form div.fields div.field div.checkbox,#register div.form div.fields div.field div.checkbox
3986 {
3987 margin: 0 0 0 184px;
3988 padding: 0;
3979 {
3980 margin: 0 0 0 184px;
3981 padding: 0;
3989 3982 }
3990 3983
3991 3984 #login div.form div.fields div.field div.checkbox label,#register div.form div.fields div.field div.checkbox label
3992 {
3993 color: #565656;
3994 font-weight: 700;
3985 {
3986 color: #565656;
3987 font-weight: 700;
3995 3988 }
3996 3989
3997 3990 #login div.form div.fields div.buttons input,#register div.form div.fields div.buttons input
3998 {
3999 color: #000;
4000 font-size: 1em;
4001 font-weight: 700;
4002 margin: 0;
3991 {
3992 color: #000;
3993 font-size: 1em;
3994 font-weight: 700;
3995 margin: 0;
4003 3996 }
4004 3997
4005 3998 #changeset_content .container .wrapper,#graph_content .container .wrapper
4006 {
4007 width: 600px;
3999 {
4000 width: 600px;
4008 4001 }
4009 4002
4010 4003 #changeset_content .container .left {
4011 float: left;
4012 width: 75%;
4013 padding-left: 5px;
4004 float: left;
4005 width: 75%;
4006 padding-left: 5px;
4014 4007 }
4015 4008
4016 4009 #changeset_content .container .left .date,.ac .match {
4017 font-weight: 700;
4018 padding-top: 5px;
4019 padding-bottom: 5px;
4010 font-weight: 700;
4011 padding-top: 5px;
4012 padding-bottom: 5px;
4020 4013 }
4021 4014
4022 4015 div#legend_container table td,div#legend_choices table td {
4023 border: none !important;
4024 height: 20px !important;
4025 padding: 0 !important;
4016 border: none !important;
4017 height: 20px !important;
4018 padding: 0 !important;
4026 4019 }
4027 4020
4028 4021 .q_filter_box {
4029 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4030 -webkit-border-radius: 4px;
4031 -moz-border-radius: 4px;
4032 border-radius: 4px;
4022 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4023 -webkit-border-radius: 4px;
4024 -moz-border-radius: 4px;
4025 border-radius: 4px;
4033 4026 border: 0 none;
4034 4027 color: #AAAAAA;
4035 4028 margin-bottom: -4px;
4036 4029 margin-top: -4px;
4037 padding-left: 3px;
4030 padding-left: 3px;
4038 4031 }
4039 4032
4040 4033 #node_filter {
4041 border: 0px solid #545454;
4042 color: #AAAAAA;
4043 padding-left: 3px;
4034 border: 0px solid #545454;
4035 color: #AAAAAA;
4036 padding-left: 3px;
4044 4037 }
4045 4038
4046 4039
4047 4040 .group_members_wrap{
4048 min-height: 85px;
4049 padding-left: 20px;
4041 min-height: 85px;
4042 padding-left: 20px;
4050 4043 }
4051 4044
4052 4045 .group_members .group_member{
4053 height: 30px;
4054 padding:0px 0px 0px 0px;
4046 height: 30px;
4047 padding:0px 0px 0px 0px;
4055 4048 }
4056 4049
4057 4050 .reviewers_member{
4058 4051 height: 15px;
4059 padding:0px 0px 0px 10px;
4052 padding:0px 0px 0px 10px;
4060 4053 }
4061 4054
4062 4055 .emails_wrap{
4063 padding: 0px 20px;
4056 padding: 0px 20px;
4064 4057 }
4065 4058
4066 4059 .emails_wrap .email_entry{
4067 4060 height: 30px;
4068 4061 padding:0px 0px 0px 10px;
4069 4062 }
4070 4063 .emails_wrap .email_entry .email{
4071 float: left
4064 float: left
4072 4065 }
4073 4066 .emails_wrap .email_entry .email_action{
4074 float: left
4067 float: left
4075 4068 }
4076 4069
4077 4070 .ips_wrap{
4078 4071 padding: 0px 20px;
4079 4072 }
4080 4073
4081 4074 .ips_wrap .ip_entry{
4082 4075 height: 30px;
4083 4076 padding:0px 0px 0px 10px;
4084 4077 }
4085 4078 .ips_wrap .ip_entry .ip{
4086 4079 float: left
4087 4080 }
4088 4081 .ips_wrap .ip_entry .ip_action{
4089 4082 float: left
4090 4083 }
4091 4084
4092 4085
4093 4086 /*README STYLE*/
4094 4087
4095 4088 div.readme {
4096 padding:0px;
4089 padding:0px;
4097 4090 }
4098 4091
4099 4092 div.readme h2 {
4100 4093 font-weight: normal;
4101 4094 }
4102 4095
4103 4096 div.readme .readme_box {
4104 4097 background-color: #fafafa;
4105 4098 }
4106 4099
4107 4100 div.readme .readme_box {
4108 4101 clear:both;
4109 4102 overflow:hidden;
4110 4103 margin:0;
4111 4104 padding:0 20px 10px;
4112 4105 }
4113 4106
4114 4107 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 {
4115 4108 border-bottom: 0 !important;
4116 4109 margin: 0 !important;
4117 4110 padding: 0 !important;
4118 4111 line-height: 1.5em !important;
4119 4112 }
4120 4113
4121 4114
4122 4115 div.readme .readme_box h1:first-child {
4123 4116 padding-top: .25em !important;
4124 4117 }
4125 4118
4126 4119 div.readme .readme_box h2, div.readme .readme_box h3 {
4127 4120 margin: 1em 0 !important;
4128 4121 }
4129 4122
4130 4123 div.readme .readme_box h2 {
4131 4124 margin-top: 1.5em !important;
4132 4125 border-top: 4px solid #e0e0e0 !important;
4133 4126 padding-top: .5em !important;
4134 4127 }
4135 4128
4136 4129 div.readme .readme_box p {
4137 4130 color: black !important;
4138 4131 margin: 1em 0 !important;
4139 4132 line-height: 1.5em !important;
4140 4133 }
4141 4134
4142 4135 div.readme .readme_box ul {
4143 4136 list-style: disc !important;
4144 4137 margin: 1em 0 1em 2em !important;
4145 4138 }
4146 4139
4147 4140 div.readme .readme_box ol {
4148 4141 list-style: decimal;
4149 4142 margin: 1em 0 1em 2em !important;
4150 4143 }
4151 4144
4152 4145 div.readme .readme_box pre, code {
4153 4146 font: 12px "Bitstream Vera Sans Mono","Courier",monospace;
4154 4147 }
4155 4148
4156 4149 div.readme .readme_box code {
4157 4150 font-size: 12px !important;
4158 4151 background-color: ghostWhite !important;
4159 4152 color: #444 !important;
4160 4153 padding: 0 .2em !important;
4161 4154 border: 1px solid #dedede !important;
4162 4155 }
4163 4156
4164 4157 div.readme .readme_box pre code {
4165 padding: 0 !important;
4166 font-size: 12px !important;
4167 background-color: #eee !important;
4168 border: none !important;
4158 padding: 0 !important;
4159 font-size: 12px !important;
4160 background-color: #eee !important;
4161 border: none !important;
4169 4162 }
4170 4163
4171 4164 div.readme .readme_box pre {
4172 margin: 1em 0;
4173 font-size: 12px;
4174 background-color: #eee;
4175 border: 1px solid #ddd;
4176 padding: 5px;
4177 color: #444;
4178 overflow: auto;
4179 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4180 -webkit-border-radius: 3px;
4181 -moz-border-radius: 3px;
4182 border-radius: 3px;
4165 margin: 1em 0;
4166 font-size: 12px;
4167 background-color: #eee;
4168 border: 1px solid #ddd;
4169 padding: 5px;
4170 color: #444;
4171 overflow: auto;
4172 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4173 -webkit-border-radius: 3px;
4174 -moz-border-radius: 3px;
4175 border-radius: 3px;
4183 4176 }
4184 4177
4185 4178 div.readme .readme_box table {
4186 4179 display: table;
4187 border-collapse: separate;
4188 border-spacing: 2px;
4189 border-color: gray;
4190 width: auto !important;
4180 border-collapse: separate;
4181 border-spacing: 2px;
4182 border-color: gray;
4183 width: auto !important;
4191 4184 }
4192 4185
4193 4186
4194 4187 /** RST STYLE **/
4195 4188
4196 4189
4197 4190 div.rst-block {
4198 4191 padding:0px;
4199 4192 }
4200 4193
4201 4194 div.rst-block h2 {
4202 4195 font-weight: normal;
4203 4196 }
4204 4197
4205 4198 div.rst-block {
4206 4199 background-color: #fafafa;
4207 4200 }
4208 4201
4209 4202 div.rst-block {
4210 4203 clear:both;
4211 4204 overflow:hidden;
4212 4205 margin:0;
4213 4206 padding:0 20px 10px;
4214 4207 }
4215 4208
4216 4209 div.rst-block h1, div.rst-block h2, div.rst-block h3, div.rst-block h4, div.rst-block h5, div.rst-block h6 {
4217 4210 border-bottom: 0 !important;
4218 4211 margin: 0 !important;
4219 4212 padding: 0 !important;
4220 4213 line-height: 1.5em !important;
4221 4214 }
4222 4215
4223 4216
4224 4217 div.rst-block h1:first-child {
4225 4218 padding-top: .25em !important;
4226 4219 }
4227 4220
4228 4221 div.rst-block h2, div.rst-block h3 {
4229 4222 margin: 1em 0 !important;
4230 4223 }
4231 4224
4232 4225 div.rst-block h2 {
4233 4226 margin-top: 1.5em !important;
4234 4227 border-top: 4px solid #e0e0e0 !important;
4235 4228 padding-top: .5em !important;
4236 4229 }
4237 4230
4238 4231 div.rst-block p {
4239 4232 color: black !important;
4240 4233 margin: 1em 0 !important;
4241 4234 line-height: 1.5em !important;
4242 4235 }
4243 4236
4244 4237 div.rst-block ul {
4245 4238 list-style: disc !important;
4246 4239 margin: 1em 0 1em 2em !important;
4247 4240 }
4248 4241
4249 4242 div.rst-block ol {
4250 4243 list-style: decimal;
4251 4244 margin: 1em 0 1em 2em !important;
4252 4245 }
4253 4246
4254 4247 div.rst-block pre, code {
4255 4248 font: 12px "Bitstream Vera Sans Mono","Courier",monospace;
4256 4249 }
4257 4250
4258 4251 div.rst-block code {
4259 4252 font-size: 12px !important;
4260 4253 background-color: ghostWhite !important;
4261 4254 color: #444 !important;
4262 4255 padding: 0 .2em !important;
4263 4256 border: 1px solid #dedede !important;
4264 4257 }
4265 4258
4266 4259 div.rst-block pre code {
4267 4260 padding: 0 !important;
4268 4261 font-size: 12px !important;
4269 4262 background-color: #eee !important;
4270 4263 border: none !important;
4271 4264 }
4272 4265
4273 4266 div.rst-block pre {
4274 4267 margin: 1em 0;
4275 4268 font-size: 12px;
4276 4269 background-color: #eee;
4277 4270 border: 1px solid #ddd;
4278 4271 padding: 5px;
4279 4272 color: #444;
4280 4273 overflow: auto;
4281 4274 -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
4282 4275 -webkit-border-radius: 3px;
4283 4276 -moz-border-radius: 3px;
4284 4277 border-radius: 3px;
4285 4278 }
4286 4279
4287 4280
4288 4281 /** comment main **/
4289 4282 .comments {
4290 4283 padding:10px 20px;
4291 4284 }
4292 4285
4293 4286 .comments .comment {
4294 4287 border: 1px solid #ddd;
4295 4288 margin-top: 10px;
4296 4289 -webkit-border-radius: 4px;
4297 4290 -moz-border-radius: 4px;
4298 border-radius: 4px;
4291 border-radius: 4px;
4299 4292 }
4300 4293
4301 4294 .comments .comment .meta {
4302 4295 background: #f8f8f8;
4303 4296 padding: 4px;
4304 4297 border-bottom: 1px solid #ddd;
4305 4298 height: 18px;
4306 4299 }
4307 4300
4308 4301 .comments .comment .meta img {
4309 4302 vertical-align: middle;
4310 4303 }
4311 4304
4312 4305 .comments .comment .meta .user {
4313 4306 font-weight: bold;
4314 4307 float: left;
4315 4308 padding: 4px 2px 2px 2px;
4316 4309 }
4317 4310
4318 4311 .comments .comment .meta .date {
4319 float: left;
4320 padding:4px 4px 0px 4px;
4312 float: left;
4313 padding:4px 4px 0px 4px;
4321 4314 }
4322 4315
4323 4316 .comments .comment .text {
4324 4317 background-color: #FAFAFA;
4325 4318 }
4326 4319 .comment .text div.rst-block p {
4327 margin: 0.5em 0px !important;
4320 margin: 0.5em 0px !important;
4328 4321 }
4329 4322
4330 4323 .comments .comments-number{
4331 padding:0px 0px 10px 0px;
4332 font-weight: bold;
4333 color: #666;
4334 font-size: 16px;
4324 padding:0px 0px 10px 0px;
4325 font-weight: bold;
4326 color: #666;
4327 font-size: 16px;
4335 4328 }
4336 4329
4337 4330 /** comment form **/
4338 4331
4339 4332 .status-block{
4340 4333 height:80px;
4341 clear:both
4334 clear:both
4342 4335 }
4343 4336
4344 4337 .comment-form .clearfix{
4345 background: #EEE;
4338 background: #EEE;
4346 4339 -webkit-border-radius: 4px;
4347 4340 -moz-border-radius: 4px;
4348 4341 border-radius: 4px;
4349 4342 padding: 10px;
4350 4343 }
4351 4344
4352 4345 div.comment-form {
4353 4346 margin-top: 20px;
4354 4347 }
4355 4348
4356 4349 .comment-form strong {
4357 4350 display: block;
4358 4351 margin-bottom: 15px;
4359 4352 }
4360 4353
4361 4354 .comment-form textarea {
4362 4355 width: 100%;
4363 4356 height: 100px;
4364 4357 font-family: 'Monaco', 'Courier', 'Courier New', monospace;
4365 4358 }
4366 4359
4367 4360 form.comment-form {
4368 4361 margin-top: 10px;
4369 4362 margin-left: 10px;
4370 4363 }
4371 4364
4372 4365 .comment-form-submit {
4373 4366 margin-top: 5px;
4374 4367 margin-left: 525px;
4375 4368 }
4376 4369
4377 4370 .file-comments {
4378 4371 display: none;
4379 4372 }
4380 4373
4381 4374 .comment-form .comment {
4382 4375 margin-left: 10px;
4383 4376 }
4384 4377
4385 4378 .comment-form .comment-help{
4386 4379 padding: 0px 0px 5px 0px;
4387 4380 color: #666;
4388 4381 }
4389 4382
4390 4383 .comment-form .comment-button{
4391 padding-top:5px;
4384 padding-top:5px;
4392 4385 }
4393 4386
4394 4387 .add-another-button {
4395 4388 margin-left: 10px;
4396 4389 margin-top: 10px;
4397 4390 margin-bottom: 10px;
4398 4391 }
4399 4392
4400 4393 .comment .buttons {
4401 float: right;
4402 padding:2px 2px 0px 0px;
4394 float: right;
4395 padding:2px 2px 0px 0px;
4403 4396 }
4404 4397
4405 4398
4406 4399 .show-inline-comments{
4407 position: relative;
4408 top:1px
4400 position: relative;
4401 top:1px
4409 4402 }
4410 4403
4411 4404 /** comment inline form **/
4412 4405 .comment-inline-form .overlay{
4413 display: none;
4406 display: none;
4414 4407 }
4415 4408 .comment-inline-form .overlay.submitting{
4416 display:block;
4409 display:block;
4417 4410 background: none repeat scroll 0 0 white;
4418 4411 font-size: 16px;
4419 4412 opacity: 0.5;
4420 4413 position: absolute;
4421 4414 text-align: center;
4422 4415 vertical-align: top;
4423 4416
4424 4417 }
4425 4418 .comment-inline-form .overlay.submitting .overlay-text{
4426 width:100%;
4427 margin-top:5%;
4419 width:100%;
4420 margin-top:5%;
4428 4421 }
4429 4422
4430 4423 .comment-inline-form .clearfix{
4431 4424 background: #EEE;
4432 4425 -webkit-border-radius: 4px;
4433 4426 -moz-border-radius: 4px;
4434 4427 border-radius: 4px;
4435 4428 padding: 5px;
4436 4429 }
4437 4430
4438 4431 div.comment-inline-form {
4439 4432 padding:4px 0px 6px 0px;
4440 4433 }
4441 4434
4442 4435
4443 4436 tr.hl-comment{
4444 4437 /*
4445 background-color: #FFFFCC !important;
4438 background-color: #FFFFCC !important;
4446 4439 */
4447 4440 }
4448 4441
4449 4442 /*
4450 4443 tr.hl-comment pre {
4451 border-top: 2px solid #FFEE33;
4452 border-left: 2px solid #FFEE33;
4453 border-right: 2px solid #FFEE33;
4444 border-top: 2px solid #FFEE33;
4445 border-left: 2px solid #FFEE33;
4446 border-right: 2px solid #FFEE33;
4454 4447 }
4455 4448 */
4456 4449
4457 4450 .comment-inline-form strong {
4458 4451 display: block;
4459 4452 margin-bottom: 15px;
4460 4453 }
4461 4454
4462 4455 .comment-inline-form textarea {
4463 4456 width: 100%;
4464 4457 height: 100px;
4465 4458 font-family: 'Monaco', 'Courier', 'Courier New', monospace;
4466 4459 }
4467 4460
4468 4461 form.comment-inline-form {
4469 4462 margin-top: 10px;
4470 4463 margin-left: 10px;
4471 4464 }
4472 4465
4473 4466 .comment-inline-form-submit {
4474 4467 margin-top: 5px;
4475 4468 margin-left: 525px;
4476 4469 }
4477 4470
4478 4471 .file-comments {
4479 4472 display: none;
4480 4473 }
4481 4474
4482 4475 .comment-inline-form .comment {
4483 4476 margin-left: 10px;
4484 4477 }
4485 4478
4486 4479 .comment-inline-form .comment-help{
4487 4480 padding: 0px 0px 2px 0px;
4488 4481 color: #666666;
4489 4482 font-size: 10px;
4490 4483 }
4491 4484
4492 4485 .comment-inline-form .comment-button{
4493 4486 padding-top:5px;
4494 4487 }
4495 4488
4496 4489 /** comment inline **/
4497 4490 .inline-comments {
4498 4491 padding:10px 20px;
4499 4492 }
4500 4493
4501 4494 .inline-comments div.rst-block {
4502 clear:both;
4503 overflow:hidden;
4504 margin:0;
4505 padding:0 20px 0px;
4495 clear:both;
4496 overflow:hidden;
4497 margin:0;
4498 padding:0 20px 0px;
4506 4499 }
4507 4500 .inline-comments .comment {
4508 4501 border: 1px solid #ddd;
4509 4502 -webkit-border-radius: 4px;
4510 4503 -moz-border-radius: 4px;
4511 4504 border-radius: 4px;
4512 4505 margin: 3px 3px 5px 5px;
4513 4506 background-color: #FAFAFA;
4514 4507 }
4515 4508 .inline-comments .add-comment {
4516 padding: 2px 4px 8px 5px;
4509 padding: 2px 4px 8px 5px;
4517 4510 }
4518 4511
4519 4512 .inline-comments .comment-wrapp{
4520 padding:1px;
4513 padding:1px;
4521 4514 }
4522 4515 .inline-comments .comment .meta {
4523 4516 background: #f8f8f8;
4524 4517 padding: 4px;
4525 4518 border-bottom: 1px solid #ddd;
4526 4519 height: 20px;
4527 4520 }
4528 4521
4529 4522 .inline-comments .comment .meta img {
4530 4523 vertical-align: middle;
4531 4524 }
4532 4525
4533 4526 .inline-comments .comment .meta .user {
4534 4527 font-weight: bold;
4535 4528 float:left;
4536 4529 padding: 3px;
4537 4530 }
4538 4531
4539 4532 .inline-comments .comment .meta .date {
4540 4533 float:left;
4541 4534 padding: 3px;
4542 4535 }
4543 4536
4544 4537 .inline-comments .comment .text {
4545 4538 background-color: #FAFAFA;
4546 4539 }
4547 4540
4548 4541 .inline-comments .comments-number{
4549 4542 padding:0px 0px 10px 0px;
4550 4543 font-weight: bold;
4551 4544 color: #666;
4552 4545 font-size: 16px;
4553 4546 }
4554 4547 .inline-comments-button .add-comment{
4555 margin:2px 0px 8px 5px !important
4548 margin:2px 0px 8px 5px !important
4556 4549 }
4557 4550
4558 4551
4559 4552 .notification-paginator{
4560 4553 padding: 0px 0px 4px 16px;
4561 float: left;
4554 float: left;
4562 4555 }
4563 4556
4564 4557 .menu_link_user{
4565 4558 padding: 10px 8px 8px 8px !important;
4566 4559 }
4567 4560
4568 4561 .menu_link_notifications {
4569 padding: 4px 4px !important;
4570 margin: 7px 4px 0px 0px !important;
4571 text-align: center;
4572 color:#888 !important;
4573 font-size: 10px;
4574 background-color: #DEDEDE !important;
4575 border-radius: 4px !important;
4576 -webkit-border-radius: 4px !important;
4577 -moz-border-radius: 4px !important;
4562 padding: 4px 4px !important;
4563 margin: 7px 4px 0px 0px !important;
4564 text-align: center;
4565 color:#888 !important;
4566 font-size: 10px;
4567 background-color: #DEDEDE !important;
4568 border-radius: 4px !important;
4569 -webkit-border-radius: 4px !important;
4570 -moz-border-radius: 4px !important;
4578 4571 }
4579 4572
4580 4573 .notification-header{
4581 padding-top:6px;
4574 padding-top:6px;
4582 4575 }
4583 4576 .notification-header .desc{
4584 font-size: 16px;
4577 font-size: 16px;
4585 4578 height: 24px;
4586 4579 float: left
4587 4580 }
4588 4581 .notification-list .container.unread{
4589 background: none repeat scroll 0 0 rgba(255, 255, 180, 0.6);
4582 background: none repeat scroll 0 0 rgba(255, 255, 180, 0.6);
4590 4583 }
4591 4584 .notification-header .gravatar{
4592 4585 background: none repeat scroll 0 0 transparent;
4593 padding: 0px 0px 0px 8px;
4586 padding: 0px 0px 0px 8px;
4594 4587 }
4595 4588 .notification-list .container .notification-header .desc{
4596 4589 font-weight: bold;
4597 4590 font-size: 17px;
4598 4591 }
4599 4592 .notification-table{
4600 border: 1px solid #ccc;
4593 border: 1px solid #ccc;
4601 4594 -webkit-border-radius: 6px 6px 6px 6px;
4602 4595 -moz-border-radius: 6px 6px 6px 6px;
4603 4596 border-radius: 6px 6px 6px 6px;
4604 4597 clear: both;
4605 4598 margin: 0px 20px 0px 20px;
4606 4599 }
4607 4600 .notification-header .delete-notifications{
4608 4601 float: right;
4609 4602 padding-top: 8px;
4610 4603 cursor: pointer;
4611 4604 }
4612 4605 .notification-header .read-notifications{
4613 4606 float: right;
4614 4607 padding-top: 8px;
4615 4608 cursor: pointer;
4616 4609 }
4617 4610 .notification-subject{
4618 4611 clear:both;
4619 4612 border-bottom: 1px solid #eee;
4620 4613 padding:5px 0px 5px 38px;
4621 4614 }
4622 4615
4623 4616 .notification-body{
4624 clear:both;
4625 margin: 34px 2px 2px 8px
4617 clear:both;
4618 margin: 34px 2px 2px 8px
4626 4619 }
4627 4620
4628 4621 /****
4629 4622 PULL REQUESTS
4630 4623 *****/
4631 4624 .pullrequests_section_head {
4632 4625 padding:10px 10px 10px 0px;
4633 4626 font-size:16px;
4634 4627 font-weight: bold;
4635 4628 }
4636 4629
4637 4630 /****
4638 4631 PERMS
4639 4632 *****/
4640 4633 #perms .perms_section_head {
4641 4634 padding:10px 10px 10px 0px;
4642 4635 font-size:16px;
4643 4636 font-weight: bold;
4644 4637 }
4645 4638
4646 4639 #perms .perm_tag{
4647 4640 padding: 1px 3px 1px 3px;
4648 4641 font-size: 10px;
4649 4642 font-weight: bold;
4650 4643 text-transform: uppercase;
4651 4644 white-space: nowrap;
4652 4645 -webkit-border-radius: 3px;
4653 4646 -moz-border-radius: 3px;
4654 4647 border-radius: 3px;
4655 4648 }
4656 4649
4657 4650 #perms .perm_tag.admin{
4658 4651 background-color: #B94A48;
4659 4652 color: #ffffff;
4660 4653 }
4661 4654
4662 4655 #perms .perm_tag.write{
4663 4656 background-color: #DB7525;
4664 color: #ffffff;
4657 color: #ffffff;
4665 4658 }
4666 4659
4667 4660 #perms .perm_tag.read{
4668 4661 background-color: #468847;
4669 color: #ffffff;
4662 color: #ffffff;
4670 4663 }
4671 4664
4672 4665 #perms .perm_tag.none{
4673 4666 background-color: #bfbfbf;
4674 color: #ffffff;
4667 color: #ffffff;
4675 4668 }
4676 4669
4677 4670 .perm-gravatar{
4678 vertical-align:middle;
4679 padding:2px;
4671 vertical-align:middle;
4672 padding:2px;
4680 4673 }
4681 4674 .perm-gravatar-ac{
4682 4675 vertical-align:middle;
4683 4676 padding:2px;
4684 4677 width: 14px;
4685 height: 14px;
4678 height: 14px;
4686 4679 }
4687 4680
4688 4681 /*****************************************************************************
4689 4682 DIFFS CSS
4690 4683 ******************************************************************************/
4691 4684
4692 4685 div.diffblock {
4693 4686 overflow: auto;
4694 4687 padding: 0px;
4695 4688 border: 1px solid #ccc;
4696 4689 background: #f8f8f8;
4697 4690 font-size: 100%;
4698 4691 line-height: 100%;
4699 4692 /* new */
4700 4693 line-height: 125%;
4701 4694 -webkit-border-radius: 6px 6px 0px 0px;
4702 4695 -moz-border-radius: 6px 6px 0px 0px;
4703 border-radius: 6px 6px 0px 0px;
4696 border-radius: 6px 6px 0px 0px;
4704 4697 }
4705 4698 div.diffblock.margined{
4706 4699 margin: 0px 20px 0px 20px;
4707 4700 }
4708 4701 div.diffblock .code-header{
4709 4702 border-bottom: 1px solid #CCCCCC;
4710 4703 background: #EEEEEE;
4711 4704 padding:10px 0 10px 0;
4712 4705 height: 14px;
4713 4706 }
4714 4707
4715 4708 div.diffblock .code-header.banner{
4716 4709 border-bottom: 1px solid #CCCCCC;
4717 4710 background: #EEEEEE;
4718 4711 height: 14px;
4719 4712 margin: 0px 95px 0px 95px;
4720 4713 padding: 3px 3px 11px 3px;
4721 4714 }
4722 4715
4723 4716 div.diffblock .code-header.cv{
4724 4717 height: 34px;
4725 4718 }
4726 4719 div.diffblock .code-header-title{
4727 padding: 0px 0px 10px 5px !important;
4728 margin: 0 !important;
4720 padding: 0px 0px 10px 5px !important;
4721 margin: 0 !important;
4729 4722 }
4730 4723 div.diffblock .code-header .hash{
4731 4724 float: left;
4732 4725 padding: 2px 0 0 2px;
4733 4726 }
4734 4727 div.diffblock .code-header .date{
4735 4728 float:left;
4736 4729 text-transform: uppercase;
4737 4730 padding: 2px 0px 0px 2px;
4738 4731 }
4739 4732 div.diffblock .code-header div{
4740 4733 margin-left:4px;
4741 4734 font-weight: bold;
4742 4735 font-size: 14px;
4743 4736 }
4744 4737
4745 4738 div.diffblock .parents {
4746 4739 float: left;
4747 4740 height: 26px;
4748 4741 width:100px;
4749 4742 font-size: 10px;
4750 4743 font-weight: 400;
4751 4744 vertical-align: middle;
4752 4745 padding: 0px 2px 2px 2px;
4753 4746 background-color:#eeeeee;
4754 4747 border-bottom: 1px solid #CCCCCC;
4755 4748 }
4756 4749
4757 4750 div.diffblock .children {
4758 4751 float: right;
4759 4752 height: 26px;
4760 4753 width:100px;
4761 4754 font-size: 10px;
4762 4755 font-weight: 400;
4763 4756 vertical-align: middle;
4764 4757 text-align: right;
4765 4758 padding: 0px 2px 2px 2px;
4766 4759 background-color:#eeeeee;
4767 4760 border-bottom: 1px solid #CCCCCC;
4768 4761 }
4769 4762
4770 4763 div.diffblock .code-body{
4771 4764 background: #FFFFFF;
4772 4765 }
4773 4766 div.diffblock pre.raw{
4774 4767 background: #FFFFFF;
4775 4768 color:#000000;
4776 4769 }
4777 4770 table.code-difftable{
4778 4771 border-collapse: collapse;
4779 4772 width: 99%;
4780 4773 }
4781 4774 table.code-difftable td {
4782 padding: 0 !important;
4783 background: none !important;
4775 padding: 0 !important;
4776 background: none !important;
4784 4777 border:0 !important;
4785 4778 vertical-align: none !important;
4786 4779 }
4787 4780 table.code-difftable .context{
4788 4781 background:none repeat scroll 0 0 #DDE7EF;
4789 4782 }
4790 4783 table.code-difftable .add{
4791 4784 background:none repeat scroll 0 0 #DDFFDD;
4792 4785 }
4793 4786 table.code-difftable .add ins{
4794 4787 background:none repeat scroll 0 0 #AAFFAA;
4795 4788 text-decoration:none;
4796 4789 }
4797 4790 table.code-difftable .del{
4798 4791 background:none repeat scroll 0 0 #FFDDDD;
4799 4792 }
4800 4793 table.code-difftable .del del{
4801 4794 background:none repeat scroll 0 0 #FFAAAA;
4802 4795 text-decoration:none;
4803 4796 }
4804 4797
4805 4798 /** LINE NUMBERS **/
4806 4799 table.code-difftable .lineno{
4807 4800
4808 4801 padding-left:2px;
4809 4802 padding-right:2px;
4810 4803 text-align:right;
4811 4804 width:32px;
4812 4805 -moz-user-select:none;
4813 4806 -webkit-user-select: none;
4814 4807 border-right: 1px solid #CCC !important;
4815 4808 border-left: 0px solid #CCC !important;
4816 4809 border-top: 0px solid #CCC !important;
4817 4810 border-bottom: none !important;
4818 4811 vertical-align: middle !important;
4819
4812
4820 4813 }
4821 4814 table.code-difftable .lineno.new {
4822 4815 }
4823 4816 table.code-difftable .lineno.old {
4824 4817 }
4825 4818 table.code-difftable .lineno a{
4826 4819 color:#747474 !important;
4827 4820 font:11px "Bitstream Vera Sans Mono",Monaco,"Courier New",Courier,monospace !important;
4828 4821 letter-spacing:-1px;
4829 4822 text-align:right;
4830 4823 padding-right: 2px;
4831 4824 cursor: pointer;
4832 4825 display: block;
4833 4826 width: 32px;
4834 4827 }
4835 4828
4836 4829 table.code-difftable .lineno-inline{
4837 4830 background:none repeat scroll 0 0 #FFF !important;
4838 4831 padding-left:2px;
4839 4832 padding-right:2px;
4840 4833 text-align:right;
4841 4834 width:30px;
4842 4835 -moz-user-select:none;
4843 4836 -webkit-user-select: none;
4844 4837 }
4845 4838
4846 4839 /** CODE **/
4847 table.code-difftable .code {
4840 table.code-difftable .code {
4848 4841 display: block;
4849 4842 width: 100%;
4850 4843 }
4851 4844 table.code-difftable .code td{
4852 4845 margin:0;
4853 4846 padding:0;
4854 4847 }
4855 4848 table.code-difftable .code pre{
4856 4849 margin:0;
4857 4850 padding:0;
4858 4851 height: 17px;
4859 4852 line-height: 17px;
4860 4853 }
4861 4854
4862 4855
4863 4856 .diffblock.margined.comm .line .code:hover{
4864 4857 background-color:#FFFFCC !important;
4865 4858 cursor: pointer !important;
4866 4859 background-image:url("../images/icons/comment_add.png") !important;
4867 4860 background-repeat:no-repeat !important;
4868 4861 background-position: right !important;
4869 4862 background-position: 0% 50% !important;
4870 4863 }
4871 4864 .diffblock.margined.comm .line .code.no-comment:hover{
4872 background-image: none !important;
4873 cursor: auto !important;
4874 background-color: inherit !important;
4875
4865 background-image: none !important;
4866 cursor: auto !important;
4867 background-color: inherit !important;
4876 4868 }
4877 4869
4878 4870 div:target {
4879 border: solid 2px #ee0 !important;
4880 margin: -2px;
4881 }
4871 border: solid 2px #ee0 !important;
4872 margin: -2px;
4873 }
@@ -1,359 +1,359 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="root.html"/>
3 3
4 4 <!-- HEADER -->
5 5 <div id="header">
6 6 <div id="header-inner" class="title hover">
7 7 <div id="logo">
8 8 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
9 9 </div>
10 10 <!-- MENU -->
11 11 ${self.page_nav()}
12 12 <!-- END MENU -->
13 13 ${self.body()}
14 14 </div>
15 15 </div>
16 16 <!-- END HEADER -->
17 17
18 18 <!-- CONTENT -->
19 19 <div id="content">
20 20 <div class="flash_msg">
21 21 <% messages = h.flash.pop_messages() %>
22 22 % if messages:
23 23 <ul id="flash-messages">
24 24 % for message in messages:
25 25 <li class="${message.category}_msg">${message}</li>
26 26 % endfor
27 27 </ul>
28 28 % endif
29 29 </div>
30 30 <div id="main">
31 31 ${next.main()}
32 32 </div>
33 33 </div>
34 34 <!-- END CONTENT -->
35 35
36 36 <!-- FOOTER -->
37 37 <div id="footer">
38 38 <div id="footer-inner" class="title">
39 39 <div>
40 40 <p class="footer-link">
41 41 <a href="${h.url('bugtracker')}">${_('Submit a bug')}</a>
42 42 </p>
43 43 <p class="footer-link-right">
44 44 <a href="${h.url('rhodecode_official')}">RhodeCode${'-%s' % c.rhodecode_instanceid if c.rhodecode_instanceid else ''}</a>
45 45 ${c.rhodecode_version} &copy; 2010-${h.datetime.today().year} by Marcin Kuzminski
46 46 </p>
47 47 </div>
48 48 </div>
49 49 </div>
50 50 <!-- END FOOTER -->
51 51
52 52 ### MAKO DEFS ###
53 53 <%def name="page_nav()">
54 54 ${self.menu()}
55 55 </%def>
56 56
57 57 <%def name="breadcrumbs()">
58 58 <div class="breadcrumbs">
59 59 ${self.breadcrumbs_links()}
60 60 </div>
61 61 </%def>
62 62
63 63 <%def name="usermenu()">
64 64 ## USER MENU
65 65 <li>
66 66 <a class="menu_link" id="quick_login_link">
67 67 <span class="icon" style="padding:5px 5px 0px 5px">
68 68 <img src="${h.gravatar_url(c.rhodecode_user.email,20)}" alt="avatar">
69 69 </span>
70 70 %if c.rhodecode_user.username != 'default':
71 71 <span class="menu_link_user">${c.rhodecode_user.username}</span>
72 72 %if c.unread_notifications != 0:
73 73 <span class="menu_link_notifications">${c.unread_notifications}</span>
74 74 %endif
75 75 %else:
76 76 <span>${_('Not logged in')}</span>
77 77 %endif
78 78 </a>
79 79
80 80 <div class="user-menu">
81 81 <div id="quick_login">
82 82 %if c.rhodecode_user.username == 'default':
83 83 <h4>${_('Login to your account')}</h4>
84 84 ${h.form(h.url('login_home',came_from=h.url.current()))}
85 85 <div class="form">
86 86 <div class="fields">
87 87 <div class="field">
88 88 <div class="label">
89 89 <label for="username">${_('Username')}:</label>
90 90 </div>
91 91 <div class="input">
92 92 ${h.text('username',class_='focus',size=40)}
93 93 </div>
94 94
95 95 </div>
96 96 <div class="field">
97 97 <div class="label">
98 98 <label for="password">${_('Password')}:</label>
99 99 </div>
100 100 <div class="input">
101 101 ${h.password('password',class_='focus',size=40)}
102 102 </div>
103 103
104 104 </div>
105 105 <div class="buttons">
106 106 <div class="password_forgoten">${h.link_to(_('Forgot password ?'),h.url('reset_password'))}</div>
107 107 <div class="register">
108 108 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
109 109 ${h.link_to(_("Don't have an account ?"),h.url('register'))}
110 110 %endif
111 111 </div>
112 112 <div class="submit">
113 113 ${h.submit('sign_in',_('Log In'),class_="ui-btn xsmall")}
114 114 </div>
115 115 </div>
116 116 </div>
117 117 </div>
118 118 ${h.end_form()}
119 119 %else:
120 120 <div class="links_left">
121 121 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
122 122 <div class="email">${c.rhodecode_user.email}</div>
123 123 <div class="big_gravatar"><img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,48)}" /></div>
124 124 <div class="inbox"><a href="${h.url('notifications')}">${_('Inbox')}: ${c.unread_notifications}</a></div>
125 125 </div>
126 126 <div class="links_right">
127 127 <ol class="links">
128 128 <li>${h.link_to(_(u'Home'),h.url('home'))}</li>
129 129 <li>${h.link_to(_(u'Journal'),h.url('journal'))}</li>
130 130 <li>${h.link_to(_(u'My account'),h.url('admin_settings_my_account'))}</li>
131 131 <li class="logout">${h.link_to(_(u'Log Out'),h.url('logout_home'))}</li>
132 132 </ol>
133 133 </div>
134 134 %endif
135 135 </div>
136 136 </div>
137 137
138 138 </li>
139 139 </%def>
140 140
141 141 <%def name="menu(current=None)">
142 142 <%
143 143 def is_current(selected):
144 144 if selected == current:
145 145 return h.literal('class="current"')
146 146 %>
147 147 <ul id="quick">
148 148 <!-- repo switcher -->
149 149 <li>
150 150 <a class="menu_link" id="repo_switcher" title="${_('Switch repository')}" href="#">
151 151 <span class="icon">
152 152 <img src="${h.url('/images/icons/database.png')}" alt="${_('Products')}" />
153 153 </span>
154 154 <span>${_('Repositories')}</span>
155 155 </a>
156 156 <ul id="repo_switcher_list" class="repo_switcher">
157 157 <li>
158 158 <a href="#">${_('loading...')}</a>
159 159 </li>
160 160 </ul>
161 161 </li>
162 162 ## we render this menu only not for those pages
163 163 %if current not in ['home','admin', 'search', 'journal']:
164 164 ##REGULAR MENU
165 165 <li ${is_current('summary')}>
166 166 <a class="menu_link" title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
167 167 <span class="icon">
168 168 <img src="${h.url('/images/icons/clipboard_16.png')}" alt="${_('Summary')}" />
169 169 </span>
170 170 <span>${_('Summary')}</span>
171 171 </a>
172 172 </li>
173 173 <li ${is_current('changelog')}>
174 174 <a class="menu_link" title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
175 175 <span class="icon">
176 176 <img src="${h.url('/images/icons/time.png')}" alt="${_('Changelog')}" />
177 177 </span>
178 178 <span>${_('Changelog')}</span>
179 179 </a>
180 180 </li>
181 181 <li ${is_current('switch_to')}>
182 182 <a class="menu_link" id="branch_tag_switcher" title="${_('Switch to')}" href="#">
183 183 <span class="icon">
184 184 <img src="${h.url('/images/icons/arrow_switch.png')}" alt="${_('Switch to')}" />
185 185 </span>
186 186 <span>${_('Switch to')}</span>
187 187 </a>
188 188 <ul id="switch_to_list" class="switch_to">
189 189 <li><a href="#">${_('loading...')}</a></li>
190 190 </ul>
191 191 </li>
192 192 <li ${is_current('files')}>
193 193 <a class="menu_link" title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
194 194 <span class="icon">
195 195 <img src="${h.url('/images/icons/file.png')}" alt="${_('Files')}" />
196 196 </span>
197 197 <span>${_('Files')}</span>
198 198 </a>
199 199 </li>
200 200 <li ${is_current('options')}>
201 201 <a class="menu_link" title="${_('Options')}" href="#">
202 202 <span class="icon">
203 203 <img src="${h.url('/images/icons/table_gear.png')}" alt="${_('Admin')}" />
204 204 </span>
205 205 <span>${_('Options')}</span>
206 206 </a>
207 207 <ul>
208 208 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
209 209 %if h.HasPermissionAll('hg.admin')('access settings on repository'):
210 210 <li>${h.link_to(_('repository settings'),h.url('edit_repo',repo_name=c.repo_name),class_='settings')}</li>
211 211 %else:
212 212 <li>${h.link_to(_('repository settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
213 213 %endif
214 214 %endif
215 215
216 216 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
217 217 %if h.is_hg(c.rhodecode_repo):
218 218 <li>${h.link_to(_('open new pull request'),h.url('pullrequest_home',repo_name=c.repo_name),class_='pull_request')}</li>
219 219 %endif
220 220 %if c.rhodecode_db_repo.fork:
221 221 <li>${h.link_to(_('compare fork'),h.url('compare_url',repo_name=c.repo_name,org_ref_type='branch',org_ref=request.GET.get('branch') or 'default',other_ref_type='branch',other_ref='default',repo=c.rhodecode_db_repo.fork.repo_name),class_='compare_request')}</li>
222 222 %endif
223 223 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
224 224
225 225 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
226 226 %if c.rhodecode_db_repo.locked[0]:
227 227 <li>${h.link_to(_('unlock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_del')}</li>
228 228 %else:
229 229 <li>${h.link_to(_('lock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_add')}</li>
230 230 %endif
231 231 %endif
232 232
233 233 % if h.HasPermissionAll('hg.admin')('access admin main page'):
234 234 <li>
235 235 ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
236 236 <%def name="admin_menu()">
237 237 <ul>
238 238 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
239 239 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
240 240 <li>${h.link_to(_('repositories groups'),h.url('repos_groups'),class_='repos_groups')}</li>
241 241 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
242 242 <li>${h.link_to(_('users groups'),h.url('users_groups'),class_='groups')}</li>
243 243 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
244 244 <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
245 245 <li>${h.link_to(_('defaults'),h.url('defaults'),class_='defaults')}</li>
246 246 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
247 247 </ul>
248 248 </%def>
249 249 ## ADMIN MENU
250 250 ${admin_menu()}
251 251 </li>
252 252 % endif
253 253 </ul>
254 254 </li>
255 255 <li>
256 256 <a class="menu_link" title="${_('Followers')}" href="${h.url('repo_followers_home',repo_name=c.repo_name)}">
257 257 <span class="icon_short">
258 258 <img src="${h.url('/images/icons/heart.png')}" alt="${_('Followers')}" />
259 259 </span>
260 260 <span id="current_followers_count" class="short">${c.repository_followers}</span>
261 261 </a>
262 262 </li>
263 263 <li>
264 264 <a class="menu_link" title="${_('Forks')}" href="${h.url('repo_forks_home',repo_name=c.repo_name)}">
265 265 <span class="icon_short">
266 266 <img src="${h.url('/images/icons/arrow_divide.png')}" alt="${_('Forks')}" />
267 267 </span>
268 268 <span class="short">${c.repository_forks}</span>
269 269 </a>
270 270 </li>
271 271 <li>
272 272 <a class="menu_link" title="${_('Pull requests')}" href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}">
273 273 <span class="icon_short">
274 274 <img src="${h.url('/images/icons/arrow_join.png')}" alt="${_('Pull requests')}" />
275 275 </span>
276 276 <span class="short">${c.repository_pull_requests}</span>
277 277 </a>
278 278 </li>
279 279 ${usermenu()}
280 280 <script type="text/javascript">
281 281 YUE.on('branch_tag_switcher','mouseover',function(){
282 282 var loaded = YUD.hasClass('branch_tag_switcher','loaded');
283 283 if(!loaded){
284 284 YUD.addClass('branch_tag_switcher','loaded');
285 285 ypjax("${h.url('branch_tag_switcher',repo_name=c.repo_name)}",'switch_to_list',
286 286 function(o){},
287 287 function(o){YUD.removeClass('branch_tag_switcher','loaded');}
288 288 ,null);
289 289 }
290 290 return false;
291 291 });
292 292 </script>
293 293 %else:
294 294 ##ROOT MENU
295 295 %if c.rhodecode_user.username != 'default':
296 296 <li ${is_current('journal')}>
297 297 <a class="menu_link" title="${_('Journal')}" href="${h.url('journal')}">
298 298 <span class="icon">
299 299 <img src="${h.url('/images/icons/book.png')}" alt="${_('Journal')}" />
300 300 </span>
301 301 <span>${_('Journal')}</span>
302 302 </a>
303 303 </li>
304 304 %else:
305 305 <li ${is_current('journal')}>
306 306 <a class="menu_link" title="${_('Public journal')}" href="${h.url('public_journal')}">
307 307 <span class="icon">
308 308 <img src="${h.url('/images/icons/book.png')}" alt="${_('Public journal')}" />
309 309 </span>
310 310 <span>${_('Public journal')}</span>
311 311 </a>
312 312 </li>
313 313 %endif
314 314 <li ${is_current('search')}>
315 315 <a class="menu_link" title="${_('Search')}" href="${h.url('search')}">
316 316 <span class="icon">
317 317 <img src="${h.url('/images/icons/search_16.png')}" alt="${_('Search')}" />
318 318 </span>
319 319 <span>${_('Search')}</span>
320 320 </a>
321 321 </li>
322 322 %if h.HasPermissionAll('hg.admin')('access admin main page'):
323 323 <li ${is_current('admin')}>
324 324 <a class="menu_link" title="${_('Admin')}" href="${h.url('admin_home')}">
325 325 <span class="icon">
326 326 <img src="${h.url('/images/icons/cog_edit.png')}" alt="${_('Admin')}" />
327 327 </span>
328 328 <span>${_('Admin')}</span>
329 329 </a>
330 330 ${admin_menu()}
331 331 </li>
332 332 %endif
333 333 ${usermenu()}
334 334 %endif
335 335 <script type="text/javascript">
336 336 YUE.on('repo_switcher','mouseover',function(){
337 337 var target = 'q_filter_rs';
338 338 var qfilter_activate = function(){
339 339 var nodes = YUQ('ul#repo_switcher_list li a.repo_name');
340 340 var func = function(node){
341 341 return node.parentNode;
342 342 }
343 343 q_filter(target,nodes,func);
344 344 }
345 345
346 346 var loaded = YUD.hasClass('repo_switcher','loaded');
347 347 if(!loaded){
348 348 YUD.addClass('repo_switcher','loaded');
349 349 ypjax("${h.url('repo_switcher')}",'repo_switcher_list',
350 350 function(o){qfilter_activate();YUD.get(target).focus()},
351 351 function(o){YUD.removeClass('repo_switcher','loaded');}
352 352 ,null);
353 353 }else{
354 YUD.get(target).focus();
354 YUD.get(target).focus();
355 355 }
356 356 return false;
357 357 });
358 358 </script>
359 359 </%def>
@@ -1,155 +1,155 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 5 <%def name="quick_menu(repo_name)">
6 6 <ul class="menu_items hidden">
7 7 <li style="border-top:1px solid #003367;margin-left:18px;padding-left:-99px"></li>
8 8 <li>
9 9 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=repo_name)}">
10 10 <span class="icon">
11 11 <img src="${h.url('/images/icons/clipboard_16.png')}" alt="${_('Summary')}" />
12 12 </span>
13 13 <span>${_('Summary')}</span>
14 14 </a>
15 15 </li>
16 16 <li>
17 17 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=repo_name)}">
18 18 <span class="icon">
19 19 <img src="${h.url('/images/icons/time.png')}" alt="${_('Changelog')}" />
20 20 </span>
21 21 <span>${_('Changelog')}</span>
22 22 </a>
23 23 </li>
24 24 <li>
25 25 <a title="${_('Files')}" href="${h.url('files_home',repo_name=repo_name)}">
26 26 <span class="icon">
27 27 <img src="${h.url('/images/icons/file.png')}" alt="${_('Files')}" />
28 28 </span>
29 29 <span>${_('Files')}</span>
30 30 </a>
31 31 </li>
32 32 <li>
33 33 <a title="${_('Fork')}" href="${h.url('repo_fork_home',repo_name=repo_name)}">
34 34 <span class="icon">
35 35 <img src="${h.url('/images/icons/arrow_divide.png')}" alt="${_('Fork')}" />
36 36 </span>
37 37 <span>${_('Fork')}</span>
38 38 </a>
39 39 </li>
40 40 </ul>
41 41 </%def>
42 42
43 43 <%def name="repo_name(name,rtype,private,fork_of,short_name=False,admin=False)">
44 44 <%
45 45 def get_name(name,short_name=short_name):
46 46 if short_name:
47 47 return name.split('/')[-1]
48 48 else:
49 49 return name
50 50 %>
51 51 <div style="white-space: nowrap">
52 52 ##TYPE OF REPO
53 53 %if h.is_hg(rtype):
54 54 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
55 55 %elif h.is_git(rtype):
56 56 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
57 57 %endif
58 58
59 59 ##PRIVATE/PUBLIC
60 60 %if private and c.visual.show_private_icon:
61 61 <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
62 62 %elif not private and c.visual.show_public_icon:
63 63 <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
64 64 %endif
65 65
66 66 ##NAME
67 67 %if admin:
68 68 ${h.link_to(get_name(name),h.url('edit_repo',repo_name=name),class_="repo_name")}
69 69 %else:
70 70 ${h.link_to(get_name(name),h.url('summary_home',repo_name=name),class_="repo_name")}
71 71 %endif
72 72 %if fork_of:
73 73 <a href="${h.url('summary_home',repo_name=fork_of.repo_name)}">
74 74 <img class="icon" alt="${_('fork')}" title="${_('Fork of')} ${fork_of.repo_name}" src="${h.url('/images/icons/arrow_divide.png')}"/></a>
75 75 %endif
76 76 </div>
77 77 </%def>
78 78
79 79 <%def name="last_change(last_change)">
80 80 <span class="tooltip" date="${last_change}" title="${h.tooltip(h.fmt_date(last_change))}">${h.age(last_change)}</span>
81 81 </%def>
82 82
83 83 <%def name="revision(name,rev,tip,author,last_msg)">
84 84 <div>
85 85 %if rev >= 0:
86 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>
87 87 %else:
88 88 ${_('No changesets yet')}
89 89 %endif
90 90 </div>
91 91 </%def>
92 92
93 93 <%def name="rss(name)">
94 94 %if c.rhodecode_user.username != 'default':
95 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>
96 96 %else:
97 97 <a title="${_('Subscribe to %s rss feed')% name}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=name)}"></a>
98 98 %endif
99 99 </%def>
100 100
101 101 <%def name="atom(name)">
102 102 %if c.rhodecode_user.username != 'default':
103 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>
104 104 %else:
105 105 <a title="${_('Subscribe to %s atom feed')% name}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=name)}"></a>
106 106 %endif
107 107 </%def>
108 108
109 109 <%def name="user_gravatar(email, size=24)">
110 110 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(email, size)}"/> </div>
111 111 </%def>
112 112
113 113 <%def name="repo_actions(repo_name, super_user=True)">
114 114 <div>
115 115 <div style="float:left">
116 116 %if super_user:
117 117 <a href="${h.url('edit_repo',repo_name=repo_name)}" title="${_('edit')}">
118 118 ${h.submit('edit_%s' % repo_name,_('edit'),class_="edit_icon action_button")}
119 119 </a>
120 120 %else:
121 121 <a href="${h.url('repo_settings_home',repo_name=repo_name)}" title="${_('edit')}">
122 122 ${h.submit('edit_%s' % repo_name,_('edit'),class_="edit_icon action_button")}
123 123 </a>
124 124 %endif
125 125 </div>
126 126 <div style="float:left">
127 127 %if super_user:
128 128 ${h.form(h.url('repo', repo_name=repo_name),method='delete')}
129 129 ${h.submit('remove_%s' % repo_name,_('delete'),class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo_name+"');")}
130 130 ${h.end_form()}
131 131 %else:
132 132 ${h.form(h.url('repo_settings_delete', repo_name=repo_name),method='delete')}
133 133 ${h.submit('remove_%s' % repo_name,_('delete'),class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo_name+"');")}
134 ${h.end_form()}
134 ${h.end_form()}
135 135 %endif
136 136 </div>
137 137 </div>
138 138 </%def>
139 139
140 140 <%def name="user_actions(user_id, username)">
141 141 ${h.form(h.url('delete_user', id=user_id),method='delete')}
142 142 ${h.submit('remove_',_('delete'),id="remove_user_%s" % user_id,
143 143 class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this user: %s') % username+"');")}
144 144 ${h.end_form()}
145 145 </%def>
146 146
147 147 <%def name="user_name(user_id, username)">
148 148 ${h.link_to(username,h.url('edit_user', id=user_id))}
149 149 </%def>
150 150
151 151 <%def name="toggle_follow(repo_id)">
152 152 <span id="follow_toggle_${repo_id}" class="following" title="${_('Stop following this repository')}"
153 153 onclick="javascript:toggleFollowingRepo(this, ${repo_id},'${str(h.get_token())}')">
154 154 </span>
155 155 </%def>
@@ -1,727 +1,727 b''
1 1 <%inherit file="/base/base.html"/>
2 2
3 3 <%def name="title()">
4 4 ${_('%s Summary') % c.repo_name} - ${c.rhodecode_name}
5 5 </%def>
6 6
7 7 <%def name="breadcrumbs_links()">
8 8 ${h.link_to(_(u'Home'),h.url('/'))}
9 9 &raquo;
10 10 ${h.repo_link(c.dbrepo.groups_and_repo)}
11 11 &raquo;
12 12 ${_('summary')}
13 13 </%def>
14 14
15 15 <%def name="page_nav()">
16 16 ${self.menu('summary')}
17 17 </%def>
18 18
19 19 <%def name="head_extra()">
20 20 <link href="${h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('repo %s ATOM feed') % c.repo_name}" type="application/atom+xml" />
21 21 <link href="${h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key)}" rel="alternate" title="${_('repo %s RSS feed') % c.repo_name}" type="application/rss+xml" />
22 22 </%def>
23 23
24 24 <%def name="main()">
25 25 <%
26 26 summary = lambda n:{False:'summary-short'}.get(n)
27 27 %>
28 28 %if c.show_stats:
29 29 <div class="box box-left">
30 30 %else:
31 31 <div class="box">
32 32 %endif
33 33 <!-- box / title -->
34 34 <div class="title">
35 35 ${self.breadcrumbs()}
36 36 </div>
37 37 <!-- end box / title -->
38 38 <div class="form">
39 39 <div id="summary" class="fields">
40 40
41 41 <div class="field">
42 42 <div class="label-summary">
43 43 <label>${_('Name')}:</label>
44 44 </div>
45 45 <div class="input ${summary(c.show_stats)}">
46 46 <div style="float:right;padding:5px 0px 0px 5px">
47 47 %if c.rhodecode_user.username != 'default':
48 48 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='rss_icon')}
49 49 ${h.link_to(_('ATOM'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='atom_icon')}
50 50 %else:
51 51 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name),class_='rss_icon')}
52 52 ${h.link_to(_('ATOM'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name),class_='atom_icon')}
53 53 %endif
54 54 </div>
55 55 %if c.rhodecode_user.username != 'default':
56 56 %if c.following:
57 57 <span id="follow_toggle" class="following tooltip" title="${_('Stop following this repository')}"
58 58 onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
59 59 </span>
60 60 %else:
61 61 <span id="follow_toggle" class="follow tooltip" title="${_('Start following this repository')}"
62 62 onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
63 63 </span>
64 64 %endif
65 65 <div style="float:right;padding:0px 0px 0px 0px">
66 66 <span class="reposize tooltip" title="${_('Click to show size of repository')}"
67 67 onclick="javascript:showRepoSize('repo_size','${c.dbrepo.repo_name}','${str(h.get_token())}')">
68 68 </span>
69 69 <span id="repo_size"></span>
70 </div>
70 </div>
71 71 %endif:
72 72
73 73 ## locking icon
74 74 %if c.rhodecode_db_repo.enable_locking:
75 75 %if c.rhodecode_db_repo.locked[0]:
76 76 <span class="locking_locked tooltip" title="${_('Repository locked by %s') % h.person_by_id(c.rhodecode_db_repo.locked[0])}"></span>
77 77 %else:
78 78 <span class="locking_unlocked tooltip" title="${_('Repository unlocked')}"></span>
79 79 %endif
80 80 %endif
81 81 ##REPO TYPE
82 82 %if h.is_hg(c.dbrepo):
83 83 <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
84 84 %endif
85 85 %if h.is_git(c.dbrepo):
86 86 <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
87 87 %endif
88 88
89 89 ##PUBLIC/PRIVATE
90 90 %if c.dbrepo.private:
91 91 <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
92 92 %else:
93 93 <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
94 94 %endif
95 95
96 96 ##REPO NAME
97 97 <span class="repo_name" title="${_('Non changable ID %s') % c.dbrepo.repo_id}">${h.repo_link(c.dbrepo.groups_and_repo)}</span>
98 98
99 99 ##FORK
100 100 %if c.dbrepo.fork:
101 101 <div style="margin-top:5px;clear:both"">
102 102 <a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}"><img class="icon" alt="${_('public')}" title="${_('Fork of')} ${c.dbrepo.fork.repo_name}" src="${h.url('/images/icons/arrow_divide.png')}"/>
103 103 ${_('Fork of')} ${c.dbrepo.fork.repo_name}
104 104 </a>
105 105 </div>
106 106 %endif
107 107 ##REMOTE
108 108 %if c.dbrepo.clone_uri:
109 109 <div style="margin-top:5px;clear:both">
110 110 <a href="${h.url(str(h.hide_credentials(c.dbrepo.clone_uri)))}"><img class="icon" alt="${_('remote clone')}" title="${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}" src="${h.url('/images/icons/connect.png')}"/>
111 111 ${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}
112 112 </a>
113 113 </div>
114 114 %endif
115 115 </div>
116 116 </div>
117 117
118 118 <div class="field">
119 119 <div class="label-summary">
120 120 <label>${_('Description')}:</label>
121 121 </div>
122 122 %if c.visual.stylify_metatags:
123 123 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(h.desc_stylize(c.dbrepo.description))}</div>
124 124 %else:
125 125 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(c.dbrepo.description)}</div>
126 126 %endif
127 127 </div>
128 128
129 129 <div class="field">
130 130 <div class="label-summary">
131 131 <label>${_('Contact')}:</label>
132 132 </div>
133 133 <div class="input ${summary(c.show_stats)}">
134 134 <div class="gravatar">
135 135 <img alt="gravatar" src="${h.gravatar_url(c.dbrepo.user.email)}"/>
136 136 </div>
137 137 ${_('Username')}: ${c.dbrepo.user.username}<br/>
138 138 ${_('Name')}: ${c.dbrepo.user.name} ${c.dbrepo.user.lastname}<br/>
139 139 ${_('Email')}: <a href="mailto:${c.dbrepo.user.email}">${c.dbrepo.user.email}</a>
140 140 </div>
141 141 </div>
142 142
143 143 <div class="field">
144 144 <div class="label-summary">
145 145 <label>${_('Clone url')}:</label>
146 146 </div>
147 147 <div class="input ${summary(c.show_stats)}">
148 148 <div style="display:none" id="clone_by_name" class="ui-btn clone">${_('Show by Name')}</div>
149 149 <div id="clone_by_id" class="ui-btn clone">${_('Show by ID')}</div>
150 150 <input style="width:80%;margin-left:105px" type="text" id="clone_url" readonly="readonly" value="${c.clone_repo_url}"/>
151 151 <input style="display:none;width:80%;margin-left:105px" type="text" id="clone_url_id" readonly="readonly" value="${c.clone_repo_url_id}"/>
152 152 </div>
153 153 </div>
154 154
155 155 <div class="field">
156 156 <div class="label-summary">
157 157 <label>${_('Trending files')}:</label>
158 158 </div>
159 159 <div class="input ${summary(c.show_stats)}">
160 160 %if c.show_stats:
161 161 <div id="lang_stats"></div>
162 162 %else:
163 163 ${_('Statistics are disabled for this repository')}
164 164 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
165 165 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
166 166 %endif
167 167 %endif
168 168 </div>
169 169 </div>
170 170
171 171 <div class="field">
172 172 <div class="label-summary">
173 173 <label>${_('Download')}:</label>
174 174 </div>
175 175 <div class="input ${summary(c.show_stats)}">
176 176 %if len(c.rhodecode_repo.revisions) == 0:
177 177 ${_('There are no downloads yet')}
178 178 %elif c.enable_downloads is False:
179 179 ${_('Downloads are disabled for this repository')}
180 180 %if h.HasPermissionAll('hg.admin')('enable downloads on from summary'):
181 181 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
182 182 %endif
183 183 %else:
184 184 ${h.select('download_options',c.rhodecode_repo.get_changeset().raw_id,c.download_options)}
185 185 <span id="${'zip_link'}">${h.link_to(_('Download as zip'), h.url('files_archive_home',repo_name=c.dbrepo.repo_name,fname='tip.zip'),class_="archive_icon ui-btn")}</span>
186 186 <span style="vertical-align: bottom">
187 187 <input id="archive_subrepos" type="checkbox" name="subrepos" />
188 188 <label for="archive_subrepos" class="tooltip" title="${h.tooltip(_('Check this to download archive with subrepos'))}" >${_('with subrepos')}</label>
189 189 </span>
190 190 %endif
191 191 </div>
192 192 </div>
193 193 </div>
194 194 </div>
195 195 </div>
196 196
197 197 %if c.show_stats:
198 198 <div class="box box-right" style="min-height:455px">
199 199 <!-- box / title -->
200 200 <div class="title">
201 201 <h5>${_('Commit activity by day / author')}</h5>
202 202 </div>
203 203
204 204 <div class="graph">
205 205 <div style="padding:0 10px 10px 17px;">
206 206 %if c.no_data:
207 207 ${c.no_data_msg}
208 208 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
209 209 ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-btn")}
210 210 %endif
211 211 %else:
212 212 ${_('Stats gathered: ')} ${c.stats_percentage}%
213 213 %endif
214 214 </div>
215 215 <div id="commit_history" style="width:450px;height:300px;float:left"></div>
216 216 <div style="clear: both;height: 10px"></div>
217 217 <div id="overview" style="width:450px;height:100px;float:left"></div>
218 218
219 219 <div id="legend_data" style="clear:both;margin-top:10px;">
220 220 <div id="legend_container"></div>
221 221 <div id="legend_choices">
222 222 <table id="legend_choices_tables" class="noborder" style="font-size:smaller;color:#545454"></table>
223 223 </div>
224 224 </div>
225 225 </div>
226 226 </div>
227 227 %endif
228 228
229 229 <div class="box">
230 230 <div class="title">
231 231 <div class="breadcrumbs">
232 232 %if c.repo_changesets:
233 233 ${h.link_to(_('Shortlog'),h.url('shortlog_home',repo_name=c.repo_name))}
234 234 %else:
235 235 ${_('Quick start')}
236 236 %endif
237 237 </div>
238 238 </div>
239 239 <div class="table">
240 240 <div id="shortlog_data">
241 241 <%include file='../shortlog/shortlog_data.html'/>
242 242 </div>
243 243 </div>
244 244 </div>
245 245
246 246 %if c.readme_data:
247 247 <div id="readme" class="anchor">
248 248 <div class="box" style="background-color: #FAFAFA">
249 249 <div class="title" title="${_("Readme file at revision '%s'" % c.rhodecode_db_repo.landing_rev)}">
250 250 <div class="breadcrumbs">
251 251 <a href="${h.url('files_home',repo_name=c.repo_name,revision='tip',f_path=c.readme_file)}">${c.readme_file}</a>
252 252 <a class="permalink" href="#readme" title="${_('Permalink to this readme')}">&para;</a>
253 253 </div>
254 254 </div>
255 255 <div class="readme">
256 256 <div class="readme_box">
257 257 ${c.readme_data|n}
258 258 </div>
259 259 </div>
260 260 </div>
261 261 </div>
262 262 %endif
263 263
264 264 <script type="text/javascript">
265 265 var clone_url = 'clone_url';
266 266 YUE.on(clone_url,'click',function(e){
267 267 if(YUD.hasClass(clone_url,'selected')){
268 268 return
269 269 }
270 270 else{
271 271 YUD.addClass(clone_url,'selected');
272 272 YUD.get(clone_url).select();
273 273 }
274 274 })
275 275
276 276 YUE.on('clone_by_name','click',function(e){
277 277 // show url by name and hide name button
278 278 YUD.setStyle('clone_url','display','');
279 279 YUD.setStyle('clone_by_name','display','none');
280 280
281 281 // hide url by id and show name button
282 282 YUD.setStyle('clone_by_id','display','');
283 283 YUD.setStyle('clone_url_id','display','none');
284 284
285 285 })
286 286 YUE.on('clone_by_id','click',function(e){
287 287
288 288 // show url by id and hide id button
289 289 YUD.setStyle('clone_by_id','display','none');
290 290 YUD.setStyle('clone_url_id','display','');
291 291
292 292 // hide url by name and show id button
293 293 YUD.setStyle('clone_by_name','display','');
294 294 YUD.setStyle('clone_url','display','none');
295 295 })
296 296
297 297
298 298 var tmpl_links = {};
299 299 %for cnt,archive in enumerate(c.rhodecode_repo._get_archives()):
300 300 tmpl_links["${archive['type']}"] = '${h.link_to('__NAME__', h.url('files_archive_home',repo_name=c.dbrepo.repo_name, fname='__CS__'+archive['extension'],subrepos='__SUB__'),class_='archive_icon ui-btn')}';
301 301 %endfor
302 302
303 303 YUE.on(['download_options','archive_subrepos'],'change',function(e){
304 304 var sm = YUD.get('download_options');
305 305 var new_cs = sm.options[sm.selectedIndex];
306 306
307 307 for(k in tmpl_links){
308 308 var s = YUD.get(k+'_link');
309 309 if(s){
310 310 var title_tmpl = "${_('Download %s as %s') % ('__CS_NAME__','__CS_EXT__')}";
311 311 title_tmpl= title_tmpl.replace('__CS_NAME__',new_cs.text);
312 312 title_tmpl = title_tmpl.replace('__CS_EXT__',k);
313 313
314 314 var url = tmpl_links[k].replace('__CS__',new_cs.value);
315 315 var subrepos = YUD.get('archive_subrepos').checked;
316 316 url = url.replace('__SUB__',subrepos);
317 317 url = url.replace('__NAME__',title_tmpl);
318 318 s.innerHTML = url
319 319 }
320 320 }
321 321 });
322 322 </script>
323 323 %if c.show_stats:
324 324 <script type="text/javascript">
325 325 var data = ${c.trending_languages|n};
326 326 var total = 0;
327 327 var no_data = true;
328 328 var tbl = document.createElement('table');
329 329 tbl.setAttribute('class','trending_language_tbl');
330 330 var cnt = 0;
331 331 for (var i=0;i<data.length;i++){
332 332 total+= data[i][1].count;
333 333 }
334 334 for (var i=0;i<data.length;i++){
335 335 cnt += 1;
336 336 no_data = false;
337 337
338 338 var hide = cnt>2;
339 339 var tr = document.createElement('tr');
340 340 if (hide){
341 341 tr.setAttribute('style','display:none');
342 342 tr.setAttribute('class','stats_hidden');
343 343 }
344 344 var k = data[i][0];
345 345 var obj = data[i][1];
346 346 var percentage = Math.round((obj.count/total*100),2);
347 347
348 348 var td1 = document.createElement('td');
349 349 td1.width = 150;
350 350 var trending_language_label = document.createElement('div');
351 351 trending_language_label.innerHTML = obj.desc+" ("+k+")";
352 352 td1.appendChild(trending_language_label);
353 353
354 354 var td2 = document.createElement('td');
355 355 td2.setAttribute('style','padding-right:14px !important');
356 356 var trending_language = document.createElement('div');
357 357 var nr_files = obj.count+" ${_('files')}";
358 358
359 359 trending_language.title = k+" "+nr_files;
360 360
361 361 if (percentage>22){
362 362 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"% "+nr_files+ "</b>";
363 363 }
364 364 else{
365 365 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"%</b>";
366 366 }
367 367
368 368 trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner');
369 369 trending_language.style.width=percentage+"%";
370 370 td2.appendChild(trending_language);
371 371
372 372 tr.appendChild(td1);
373 373 tr.appendChild(td2);
374 374 tbl.appendChild(tr);
375 375 if(cnt == 3){
376 376 var show_more = document.createElement('tr');
377 377 var td = document.createElement('td');
378 378 lnk = document.createElement('a');
379 379
380 380 lnk.href='#';
381 381 lnk.innerHTML = "${_('show more')}";
382 382 lnk.id='code_stats_show_more';
383 383 td.appendChild(lnk);
384 384
385 385 show_more.appendChild(td);
386 386 show_more.appendChild(document.createElement('td'));
387 387 tbl.appendChild(show_more);
388 388 }
389 389
390 390 }
391 391
392 392 YUD.get('lang_stats').appendChild(tbl);
393 393 YUE.on('code_stats_show_more','click',function(){
394 394 l = YUD.getElementsByClassName('stats_hidden')
395 395 for (e in l){
396 396 YUD.setStyle(l[e],'display','');
397 397 };
398 398 YUD.setStyle(YUD.get('code_stats_show_more'),
399 399 'display','none');
400 400 });
401 401 </script>
402 402 <script type="text/javascript">
403 403 /**
404 404 * Plots summary graph
405 405 *
406 406 * @class SummaryPlot
407 407 * @param {from} initial from for detailed graph
408 408 * @param {to} initial to for detailed graph
409 409 * @param {dataset}
410 410 * @param {overview_dataset}
411 411 */
412 412 function SummaryPlot(from,to,dataset,overview_dataset) {
413 413 var initial_ranges = {
414 414 "xaxis":{
415 415 "from":from,
416 416 "to":to,
417 417 },
418 418 };
419 419 var dataset = dataset;
420 420 var overview_dataset = [overview_dataset];
421 421 var choiceContainer = YUD.get("legend_choices");
422 422 var choiceContainerTable = YUD.get("legend_choices_tables");
423 423 var plotContainer = YUD.get('commit_history');
424 424 var overviewContainer = YUD.get('overview');
425 425
426 426 var plot_options = {
427 427 bars: {show:true,align:'center',lineWidth:4},
428 428 legend: {show:true, container:"legend_container"},
429 429 points: {show:true,radius:0,fill:false},
430 430 yaxis: {tickDecimals:0,},
431 431 xaxis: {
432 432 mode: "time",
433 433 timeformat: "%d/%m",
434 434 min:from,
435 435 max:to,
436 436 },
437 437 grid: {
438 438 hoverable: true,
439 439 clickable: true,
440 440 autoHighlight:true,
441 441 color: "#999"
442 442 },
443 443 //selection: {mode: "x"}
444 444 };
445 445 var overview_options = {
446 446 legend:{show:false},
447 447 bars: {show:true,barWidth: 2,},
448 448 shadowSize: 0,
449 449 xaxis: {mode: "time", timeformat: "%d/%m/%y",},
450 450 yaxis: {ticks: 3, min: 0,tickDecimals:0,},
451 451 grid: {color: "#999",},
452 452 selection: {mode: "x"}
453 453 };
454 454
455 455 /**
456 456 *get dummy data needed in few places
457 457 */
458 458 function getDummyData(label){
459 459 return {"label":label,
460 460 "data":[{"time":0,
461 461 "commits":0,
462 462 "added":0,
463 463 "changed":0,
464 464 "removed":0,
465 465 }],
466 466 "schema":["commits"],
467 467 "color":'#ffffff',
468 468 }
469 469 }
470 470
471 471 /**
472 472 * generate checkboxes accordindly to data
473 473 * @param keys
474 474 * @returns
475 475 */
476 476 function generateCheckboxes(data) {
477 477 //append checkboxes
478 478 var i = 0;
479 479 choiceContainerTable.innerHTML = '';
480 480 for(var pos in data) {
481 481
482 482 data[pos].color = i;
483 483 i++;
484 484 if(data[pos].label != ''){
485 485 choiceContainerTable.innerHTML +=
486 486 '<tr><td><input type="checkbox" id="id_user_{0}" name="{0}" checked="checked" /> \
487 487 <label for="id_user_{0}">{0}</label></td></tr>'.format(data[pos].label);
488 488 }
489 489 }
490 490 }
491 491
492 492 /**
493 493 * ToolTip show
494 494 */
495 495 function showTooltip(x, y, contents) {
496 496 var div=document.getElementById('tooltip');
497 497 if(!div) {
498 498 div = document.createElement('div');
499 499 div.id="tooltip";
500 500 div.style.position="absolute";
501 501 div.style.border='1px solid #fdd';
502 502 div.style.padding='2px';
503 503 div.style.backgroundColor='#fee';
504 504 document.body.appendChild(div);
505 505 }
506 506 YUD.setStyle(div, 'opacity', 0);
507 507 div.innerHTML = contents;
508 508 div.style.top=(y + 5) + "px";
509 509 div.style.left=(x + 5) + "px";
510 510
511 511 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
512 512 anim.animate();
513 513 }
514 514
515 515 /**
516 516 * This function will detect if selected period has some changesets
517 517 for this user if it does this data is then pushed for displaying
518 518 Additionally it will only display users that are selected by the checkbox
519 519 */
520 520 function getDataAccordingToRanges(ranges) {
521 521
522 522 var data = [];
523 523 var new_dataset = {};
524 524 var keys = [];
525 525 var max_commits = 0;
526 526 for(var key in dataset){
527 527
528 528 for(var ds in dataset[key].data){
529 529 commit_data = dataset[key].data[ds];
530 530 if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){
531 531
532 532 if(new_dataset[key] === undefined){
533 533 new_dataset[key] = {data:[],schema:["commits"],label:key};
534 534 }
535 535 new_dataset[key].data.push(commit_data);
536 536 }
537 537 }
538 538 if (new_dataset[key] !== undefined){
539 539 data.push(new_dataset[key]);
540 540 }
541 541 }
542 542
543 543 if (data.length > 0){
544 544 return data;
545 545 }
546 546 else{
547 547 //just return dummy data for graph to plot itself
548 548 return [getDummyData('')];
549 549 }
550 550 }
551 551
552 552 /**
553 553 * redraw using new checkbox data
554 554 */
555 555 function plotchoiced(e,args){
556 556 var cur_data = args[0];
557 557 var cur_ranges = args[1];
558 558
559 559 var new_data = [];
560 560 var inputs = choiceContainer.getElementsByTagName("input");
561 561
562 562 //show only checked labels
563 563 for(var i=0; i<inputs.length; i++) {
564 564 var checkbox_key = inputs[i].name;
565 565
566 566 if(inputs[i].checked){
567 567 for(var d in cur_data){
568 568 if(cur_data[d].label == checkbox_key){
569 569 new_data.push(cur_data[d]);
570 570 }
571 571 }
572 572 }
573 573 else{
574 574 //push dummy data to not hide the label
575 575 new_data.push(getDummyData(checkbox_key));
576 576 }
577 577 }
578 578
579 579 var new_options = YAHOO.lang.merge(plot_options, {
580 580 xaxis: {
581 581 min: cur_ranges.xaxis.from,
582 582 max: cur_ranges.xaxis.to,
583 583 mode:"time",
584 584 timeformat: "%d/%m",
585 585 },
586 586 });
587 587 if (!new_data){
588 588 new_data = [[0,1]];
589 589 }
590 590 // do the zooming
591 591 plot = YAHOO.widget.Flot(plotContainer, new_data, new_options);
592 592
593 593 plot.subscribe("plotselected", plotselected);
594 594
595 595 //resubscribe plothover
596 596 plot.subscribe("plothover", plothover);
597 597
598 598 // don't fire event on the overview to prevent eternal loop
599 599 overview.setSelection(cur_ranges, true);
600 600
601 601 }
602 602
603 603 /**
604 604 * plot only selected items from overview
605 605 * @param ranges
606 606 * @returns
607 607 */
608 608 function plotselected(ranges,cur_data) {
609 609 //updates the data for new plot
610 610 var data = getDataAccordingToRanges(ranges);
611 611 generateCheckboxes(data);
612 612
613 613 var new_options = YAHOO.lang.merge(plot_options, {
614 614 xaxis: {
615 615 min: ranges.xaxis.from,
616 616 max: ranges.xaxis.to,
617 617 mode:"time",
618 618 timeformat: "%d/%m",
619 619 },
620 620 });
621 621 // do the zooming
622 622 plot = YAHOO.widget.Flot(plotContainer, data, new_options);
623 623
624 624 plot.subscribe("plotselected", plotselected);
625 625
626 626 //resubscribe plothover
627 627 plot.subscribe("plothover", plothover);
628 628
629 629 // don't fire event on the overview to prevent eternal loop
630 630 overview.setSelection(ranges, true);
631 631
632 632 //resubscribe choiced
633 633 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]);
634 634 }
635 635
636 636 var previousPoint = null;
637 637
638 638 function plothover(o) {
639 639 var pos = o.pos;
640 640 var item = o.item;
641 641
642 642 //YUD.get("x").innerHTML = pos.x.toFixed(2);
643 643 //YUD.get("y").innerHTML = pos.y.toFixed(2);
644 644 if (item) {
645 645 if (previousPoint != item.datapoint) {
646 646 previousPoint = item.datapoint;
647 647
648 648 var tooltip = YUD.get("tooltip");
649 649 if(tooltip) {
650 650 tooltip.parentNode.removeChild(tooltip);
651 651 }
652 652 var x = item.datapoint.x.toFixed(2);
653 653 var y = item.datapoint.y.toFixed(2);
654 654
655 655 if (!item.series.label){
656 656 item.series.label = 'commits';
657 657 }
658 658 var d = new Date(x*1000);
659 659 var fd = d.toDateString()
660 660 var nr_commits = parseInt(y);
661 661
662 662 var cur_data = dataset[item.series.label].data[item.dataIndex];
663 663 var added = cur_data.added;
664 664 var changed = cur_data.changed;
665 665 var removed = cur_data.removed;
666 666
667 667 var nr_commits_suffix = " ${_('commits')} ";
668 668 var added_suffix = " ${_('files added')} ";
669 669 var changed_suffix = " ${_('files changed')} ";
670 670 var removed_suffix = " ${_('files removed')} ";
671 671
672 672
673 673 if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
674 674 if(added==1){added_suffix=" ${_('file added')} ";}
675 675 if(changed==1){changed_suffix=" ${_('file changed')} ";}
676 676 if(removed==1){removed_suffix=" ${_('file removed')} ";}
677 677
678 678 showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
679 679 +'<br/>'+
680 680 nr_commits + nr_commits_suffix+'<br/>'+
681 681 added + added_suffix +'<br/>'+
682 682 changed + changed_suffix + '<br/>'+
683 683 removed + removed_suffix + '<br/>');
684 684 }
685 685 }
686 686 else {
687 687 var tooltip = YUD.get("tooltip");
688 688
689 689 if(tooltip) {
690 690 tooltip.parentNode.removeChild(tooltip);
691 691 }
692 692 previousPoint = null;
693 693 }
694 694 }
695 695
696 696 /**
697 697 * MAIN EXECUTION
698 698 */
699 699
700 700 var data = getDataAccordingToRanges(initial_ranges);
701 701 generateCheckboxes(data);
702 702
703 703 //main plot
704 704 var plot = YAHOO.widget.Flot(plotContainer,data,plot_options);
705 705
706 706 //overview
707 707 var overview = YAHOO.widget.Flot(overviewContainer,
708 708 overview_dataset, overview_options);
709 709
710 710 //show initial selection on overview
711 711 overview.setSelection(initial_ranges);
712 712
713 713 plot.subscribe("plotselected", plotselected);
714 714 plot.subscribe("plothover", plothover)
715 715
716 716 overview.subscribe("plotselected", function (ranges) {
717 717 plot.setSelection(ranges);
718 718 });
719 719
720 720 // user choices on overview
721 721 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
722 722 }
723 723 SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n});
724 724 </script>
725 725 %endif
726 726
727 727 </%def>
General Comments 0
You need to be logged in to leave comments. Login now