Commit eca823c1c7cef45cc18c6ab36d2327650c85bfc3
Exists in
master
and in
4 other branches
Merge branch 'master' into api
Showing
125 changed files
with
1752 additions
and
666 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 125 files displayed.
.gitignore
CHANGELOG
Gemfile
... | ... | @@ -7,7 +7,7 @@ gem "sqlite3" |
7 | 7 | gem "mysql2" |
8 | 8 | |
9 | 9 | # Auth |
10 | -gem "devise", "~> 1.5" | |
10 | +gem "devise", "~> 2.1.0" | |
11 | 11 | |
12 | 12 | # GITLAB patched libs |
13 | 13 | gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837" |
... | ... | @@ -71,7 +71,6 @@ group :development, :test do |
71 | 71 | gem "awesome_print" |
72 | 72 | gem "database_cleaner" |
73 | 73 | gem "launchy" |
74 | - gem "webmock" | |
75 | 74 | end |
76 | 75 | |
77 | 76 | group :test do |
... | ... | @@ -82,4 +81,5 @@ group :test do |
82 | 81 | gem "shoulda-matchers" |
83 | 82 | gem 'email_spec' |
84 | 83 | gem 'resque_spec' |
84 | + gem "webmock" | |
85 | 85 | end | ... | ... |
Gemfile.lock
... | ... | @@ -148,10 +148,11 @@ GEM |
148 | 148 | nokogiri (>= 1.5.0) |
149 | 149 | daemons (1.1.8) |
150 | 150 | database_cleaner (0.8.0) |
151 | - devise (1.5.3) | |
151 | + devise (2.1.2) | |
152 | 152 | bcrypt-ruby (~> 3.0) |
153 | - orm_adapter (~> 0.0.3) | |
154 | - warden (~> 1.1) | |
153 | + orm_adapter (~> 0.1) | |
154 | + railties (~> 3.1) | |
155 | + warden (~> 1.2.1) | |
155 | 156 | diff-lcs (1.1.3) |
156 | 157 | drapper (0.8.4) |
157 | 158 | email_spec (1.2.1) |
... | ... | @@ -225,7 +226,7 @@ GEM |
225 | 226 | omniauth (1.1.0) |
226 | 227 | hashie (~> 1.2) |
227 | 228 | rack |
228 | - orm_adapter (0.0.7) | |
229 | + orm_adapter (0.3.0) | |
229 | 230 | polyglot (0.3.3) |
230 | 231 | posix-spawn (0.3.6) |
231 | 232 | pry (0.9.9.6) |
... | ... | @@ -356,7 +357,7 @@ GEM |
356 | 357 | raindrops (~> 0.7) |
357 | 358 | vegas (0.1.11) |
358 | 359 | rack (>= 1.0.0) |
359 | - warden (1.2.0) | |
360 | + warden (1.2.1) | |
360 | 361 | rack (>= 1.0) |
361 | 362 | webmock (1.8.7) |
362 | 363 | addressable (>= 2.2.7) |
... | ... | @@ -383,7 +384,7 @@ DEPENDENCIES |
383 | 384 | colored |
384 | 385 | cucumber-rails |
385 | 386 | database_cleaner |
386 | - devise (~> 1.5) | |
387 | + devise (~> 2.1.0) | |
387 | 388 | drapper |
388 | 389 | email_spec |
389 | 390 | ffaker | ... | ... |
VERSION
6.38 KB
app/assets/javascripts/application.js
... | ... | @@ -12,6 +12,7 @@ |
12 | 12 | //= require jquery.cookie |
13 | 13 | //= require jquery.endless-scroll |
14 | 14 | //= require jquery.highlight |
15 | +//= require jquery.waitforimages | |
15 | 16 | //= require bootstrap-modal |
16 | 17 | //= require modernizr |
17 | 18 | //= require chosen-jquery |
... | ... | @@ -20,10 +21,26 @@ |
20 | 21 | //= require_tree . |
21 | 22 | |
22 | 23 | $(document).ready(function(){ |
24 | + | |
23 | 25 | $(".one_click_select").live("click", function(){ |
24 | 26 | $(this).select(); |
25 | 27 | }); |
26 | 28 | |
29 | + | |
30 | + $('body').on('ajax:complete, ajax:beforeSend, submit', 'form', function(e){ | |
31 | + var buttons = $('[type="submit"]', this); | |
32 | + switch( e.type ){ | |
33 | + case 'ajax:beforeSend': | |
34 | + case 'submit': | |
35 | + buttons.attr('disabled', 'disabled'); | |
36 | + break; | |
37 | + case ' ajax:complete': | |
38 | + default: | |
39 | + buttons.removeAttr('disabled'); | |
40 | + break; | |
41 | + } | |
42 | + }) | |
43 | + | |
27 | 44 | $(".account-box").mouseenter(showMenu); |
28 | 45 | $(".account-box").mouseleave(resetMenu); |
29 | 46 | |
... | ... | @@ -97,3 +114,8 @@ function showDiff(link) { |
97 | 114 | return _chosen.apply(this, [default_options]); |
98 | 115 | }}) |
99 | 116 | })(jQuery); |
117 | + | |
118 | + | |
119 | +function ajaxGet(url) { | |
120 | + $.ajax({type: "GET", url: url, dataType: "script"}); | |
121 | +} | ... | ... |
app/assets/javascripts/issues.js
... | ... | @@ -73,4 +73,25 @@ function issuesPage(){ |
73 | 73 | $("#milestone_id, #assignee_id, #label_name").on("change", function(){ |
74 | 74 | $(this).closest("form").submit(); |
75 | 75 | }); |
76 | + | |
77 | + $('body').on('ajax:success', '.close_issue, .reopen_issue, #new_issue', function(){ | |
78 | + var t = $(this), | |
79 | + totalIssues, | |
80 | + reopen = t.hasClass('reopen_issue'), | |
81 | + newIssue = false; | |
82 | + if( this.id == 'new_issue' ){ | |
83 | + newIssue = true; | |
84 | + } | |
85 | + $('.issue_counter, #new_issue').each(function(){ | |
86 | + var issue = $(this); | |
87 | + totalIssues = parseInt( $(this).html(), 10 ); | |
88 | + | |
89 | + if( newIssue || ( reopen && issue.closest('.main_menu').length ) ){ | |
90 | + $(this).html( totalIssues+1 ); | |
91 | + }else { | |
92 | + $(this).html( totalIssues-1 ); | |
93 | + } | |
94 | + }); | |
95 | + | |
96 | + }); | |
76 | 97 | } | ... | ... |
app/assets/javascripts/note.js
... | ... | @@ -25,11 +25,11 @@ init: |
25 | 25 | $(this).closest('li').fadeOut(); }); |
26 | 26 | |
27 | 27 | $("#new_note").live("ajax:before", function(){ |
28 | - $("#submit_note").attr("disabled", "disabled"); | |
28 | + $(".submit_note").attr("disabled", "disabled"); | |
29 | 29 | }) |
30 | 30 | |
31 | 31 | $("#new_note").live("ajax:complete", function(){ |
32 | - $("#submit_note").removeAttr("disabled"); | |
32 | + $(".submit_note").removeAttr("disabled"); | |
33 | 33 | }) |
34 | 34 | |
35 | 35 | $("#note_note").live("focus", function(){ | ... | ... |
app/assets/stylesheets/common.scss
app/assets/stylesheets/gitlab_bootstrap.scss
... | ... | @@ -202,6 +202,10 @@ a:focus { |
202 | 202 | color:$style_color; |
203 | 203 | } |
204 | 204 | |
205 | +.nav-tabs > .active > a { | |
206 | + font-weight:bold; | |
207 | +} | |
208 | + | |
205 | 209 | /** COLORS **/ |
206 | 210 | .cgray { color:gray; } |
207 | 211 | .cred { color:#D12F19; } |
... | ... | @@ -209,6 +213,7 @@ a:focus { |
209 | 213 | .cblack { color:#111; } |
210 | 214 | .cdark { color:#444 } |
211 | 215 | .cwhite { color:#fff !important } |
216 | +.bgred { background: #F2DEDE !important} | |
212 | 217 | |
213 | 218 | /** COMMON STYLES **/ |
214 | 219 | .left { |
... | ... | @@ -299,9 +304,24 @@ table.no-borders { |
299 | 304 | } |
300 | 305 | |
301 | 306 | .event_label { |
302 | - background: #FCEEC1; | |
303 | - padding: 2px 2px 0; | |
304 | - font-family: monospace; | |
307 | + @extend .label; | |
308 | + background-color: #999; | |
309 | + | |
310 | + &.pushed { | |
311 | + background-color: #3A87AD; | |
312 | + } | |
313 | + | |
314 | + &.opened { | |
315 | + background-color: #468847; | |
316 | + } | |
317 | + | |
318 | + &.closed { | |
319 | + background-color: #B94A48; | |
320 | + } | |
321 | + | |
322 | + &.merged { | |
323 | + background-color: #2A2; | |
324 | + } | |
305 | 325 | } |
306 | 326 | |
307 | 327 | img.avatar { |
... | ... | @@ -425,9 +445,10 @@ form { |
425 | 445 | */ |
426 | 446 | .ui-box { |
427 | 447 | background:#F9F9F9; |
428 | - margin-bottom: 40px; | |
448 | + margin-bottom: 25px; | |
429 | 449 | @include round-borders-all(4px); |
430 | 450 | border-color: #CCC; |
451 | + @include solid_shade; | |
431 | 452 | |
432 | 453 | ul { |
433 | 454 | margin:0; |
... | ... | @@ -443,6 +464,13 @@ form { |
443 | 464 | background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); |
444 | 465 | background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); |
445 | 466 | |
467 | + &.small { | |
468 | + line-height: 28px; | |
469 | + font-size: 14px; | |
470 | + line-height:28px; | |
471 | + text-shadow: 0 1px 1px white; | |
472 | + } | |
473 | + | |
446 | 474 | form { |
447 | 475 | padding:9px 0; |
448 | 476 | margin:0px; |
... | ... | @@ -511,6 +539,7 @@ form { |
511 | 539 | table.admin-table { |
512 | 540 | @extend .table-bordered; |
513 | 541 | @extend .zebra-striped; |
542 | + @include solid_shade; | |
514 | 543 | th { |
515 | 544 | border-color: #CCC; |
516 | 545 | border-bottom: 1px solid #bbb; |
... | ... | @@ -568,6 +597,8 @@ ul.breadcrumb { |
568 | 597 | @extend .prepend-top-20; |
569 | 598 | @extend .append-bottom-20; |
570 | 599 | border-width:1px; |
600 | + @include solid_shade; | |
601 | + | |
571 | 602 | |
572 | 603 | img { max-width: 100%; } |
573 | 604 | |
... | ... | @@ -624,13 +655,166 @@ p { |
624 | 655 | h3.page_title { |
625 | 656 | color:#456; |
626 | 657 | font-size:20px; |
627 | - font-weight: 600; | |
658 | + font-weight: normal; | |
628 | 659 | line-height: 28px; |
629 | 660 | } |
630 | 661 | |
631 | -pre.logs { | |
632 | - .log { | |
633 | - font-size:12px; | |
634 | - line-height:18px; | |
662 | +/** | |
663 | + * File content holder | |
664 | + * | |
665 | + */ | |
666 | +.file_holder { | |
667 | + border:1px solid #CCC; | |
668 | + margin-bottom:1em; | |
669 | + @include solid_shade; | |
670 | + | |
671 | + .file_title { | |
672 | + border-bottom: 1px solid #bbb; | |
673 | + background:#eee; | |
674 | + background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); | |
675 | + background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); | |
676 | + background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); | |
677 | + background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); | |
678 | + margin: 0; | |
679 | + font-weight: normal; | |
680 | + font-weight: bold; | |
681 | + text-align: left; | |
682 | + color: #666; | |
683 | + padding: 9px 10px; | |
684 | + height:18px; | |
685 | + | |
686 | + .options { | |
687 | + float:right; | |
688 | + margin-top: -5px; | |
689 | + } | |
690 | + | |
691 | + .file_name { | |
692 | + color:$style_color; | |
693 | + font-size:14px; | |
694 | + text-shadow: 0 1px 1px #fff; | |
695 | + small { | |
696 | + color:#999; | |
697 | + font-size:13px; | |
698 | + } | |
699 | + } | |
700 | + } | |
701 | + .file_content { | |
702 | + background:#fff; | |
703 | + font-size: 11px; | |
704 | + | |
705 | + &.wiki { | |
706 | + font-size: 13px; | |
707 | + code { | |
708 | + padding:0 4px; | |
709 | + } | |
710 | + padding:20px; | |
711 | + h1, h2 { | |
712 | + line-height: 46px; | |
713 | + } | |
714 | + h3, h4 { | |
715 | + line-height: 40px; | |
716 | + } | |
717 | + } | |
718 | + | |
719 | + &.image_file { | |
720 | + background:#eee; | |
721 | + text-align:center; | |
722 | + img { | |
723 | + padding:100px; | |
724 | + max-width:300px; | |
725 | + } | |
726 | + } | |
727 | + | |
728 | + &.blob_file { | |
729 | + | |
730 | + } | |
731 | + | |
732 | + /** | |
733 | + * Blame file | |
734 | + */ | |
735 | + &.blame { | |
736 | + tr { | |
737 | + border-bottom: 1px solid #eee; | |
738 | + } | |
739 | + td { | |
740 | + padding:5px; | |
741 | + } | |
742 | + .author, | |
743 | + .blame_commit { | |
744 | + background:#f5f5f5; | |
745 | + vertical-align:top; | |
746 | + } | |
747 | + .lines { | |
748 | + pre { | |
749 | + padding:0; | |
750 | + margin:0; | |
751 | + background:none; | |
752 | + border:none; | |
753 | + } | |
754 | + } | |
755 | + } | |
756 | + | |
757 | + &.logs { | |
758 | + background:#eee; | |
759 | + max-height: 700px; | |
760 | + overflow-y: auto; | |
761 | + | |
762 | + ol { | |
763 | + margin-left:40px; | |
764 | + padding: 10px 0; | |
765 | + border-left: 1px solid #CCC; | |
766 | + margin-bottom:0; | |
767 | + background: white; | |
768 | + li { | |
769 | + color:#888; | |
770 | + p { | |
771 | + margin:0; | |
772 | + color:#333; | |
773 | + line-height:24px; | |
774 | + padding-left: 10px; | |
775 | + } | |
776 | + | |
777 | + &:hover { | |
778 | + background:$hover; | |
779 | + } | |
780 | + } | |
781 | + } | |
782 | + } | |
783 | + | |
784 | + /** | |
785 | + * Code file | |
786 | + */ | |
787 | + &.code { | |
788 | + padding:0; | |
789 | + td.code { | |
790 | + width: 100%; | |
791 | + .highlight { | |
792 | + margin-left: 55px; | |
793 | + overflow:auto; | |
794 | + overflow-y:hidden; | |
795 | + } | |
796 | + } | |
797 | + .highlight pre { | |
798 | + white-space: pre; | |
799 | + word-wrap:normal; | |
800 | + } | |
801 | + | |
802 | + table.highlighttable { | |
803 | + border: none; | |
804 | + } | |
805 | + body.project-page table.highlighttable td { border: none } | |
806 | + table.highlighttable tr:hover { background:none;} | |
807 | + | |
808 | + table.highlighttable pre{ | |
809 | + line-height:16px !important; | |
810 | + font-size:12px !important; | |
811 | + } | |
812 | + | |
813 | + table.highlighttable .linenodiv pre { | |
814 | + text-align: right; | |
815 | + padding-right: 4px; | |
816 | + color:#666; | |
817 | + } | |
818 | + } | |
635 | 819 | } |
636 | 820 | } | ... | ... |
app/assets/stylesheets/header.scss
... | ... | @@ -96,7 +96,7 @@ header { |
96 | 96 | */ |
97 | 97 | .search { |
98 | 98 | float: right; |
99 | - margin-right: 55px; | |
99 | + margin-right: 50px; | |
100 | 100 | |
101 | 101 | .search-input { |
102 | 102 | @extend .span2; |
... | ... | @@ -126,10 +126,10 @@ header { |
126 | 126 | cursor: pointer; |
127 | 127 | img { |
128 | 128 | border-radius: 4px; |
129 | - right: 0px; | |
129 | + right: 5px; | |
130 | 130 | position: absolute; |
131 | - width: 33px; | |
132 | - height: 33px; | |
131 | + width: 31px; | |
132 | + height: 31px; | |
133 | 133 | display: block; |
134 | 134 | top: 0; |
135 | 135 | &:after { | ... | ... |
app/assets/stylesheets/main.scss
... | ... | @@ -31,6 +31,12 @@ $hover: #FDF5D9; |
31 | 31 | box-shadow: 0 0 3px #ddd; |
32 | 32 | } |
33 | 33 | |
34 | +@mixin solid_shade { | |
35 | + -moz-box-shadow: 0 0 0 3px #eee; | |
36 | + -webkit-box-shadow: 0 0 0 3px #eee; | |
37 | + box-shadow: 0 0 0 3px #eee; | |
38 | +} | |
39 | + | |
34 | 40 | @mixin border-radius($radius) { |
35 | 41 | -moz-border-radius: $radius; |
36 | 42 | -webkit-border-radius: $radius; |
... | ... | @@ -136,7 +142,7 @@ $hover: #FDF5D9; |
136 | 142 | /** |
137 | 143 | * Code (files list) styles. Browsing project files there |
138 | 144 | */ |
139 | -@import "tree.scss"; | |
145 | +@import "sections/tree.scss"; | |
140 | 146 | |
141 | 147 | /** |
142 | 148 | * This file represent notes(comments) styles | ... | ... |
app/assets/stylesheets/notes.scss
... | ... | @@ -63,18 +63,22 @@ p.notify_controls span{ |
63 | 63 | |
64 | 64 | tr.line_notes_row { |
65 | 65 | border-bottom:1px solid #DDD; |
66 | + border-left: 7px solid #2A79A3; | |
67 | + | |
66 | 68 | &.reply { |
67 | 69 | background:#eee; |
68 | - | |
70 | + border-left: 7px solid #2A79A3; | |
71 | + border-top:1px solid #ddd; | |
69 | 72 | td { |
70 | 73 | padding:7px 10px; |
71 | 74 | } |
72 | 75 | a.line_note_reply_link { |
73 | 76 | @include round-borders-all(4px); |
74 | - border-color:#aaa; | |
75 | - background: #bbb; | |
76 | - padding: 3px 20px; | |
77 | + padding: 3px 10px; | |
78 | + margin-left:5px; | |
77 | 79 | color: white; |
80 | + background: #2A79A3; | |
81 | + border-color: #2A79A3; | |
78 | 82 | } |
79 | 83 | } |
80 | 84 | ul { |
... | ... | @@ -95,6 +99,9 @@ tr.line_notes_row { |
95 | 99 | td { |
96 | 100 | border-bottom:1px solid #ddd; |
97 | 101 | } |
102 | + .actions { | |
103 | + margin:0; | |
104 | + } | |
98 | 105 | } |
99 | 106 | |
100 | 107 | td .line_note_link { | ... | ... |
app/assets/stylesheets/sections/commits.scss
... | ... | @@ -101,18 +101,21 @@ |
101 | 101 | margin:50px; |
102 | 102 | padding:1px; |
103 | 103 | max-width:400px; |
104 | - } | |
105 | - &.diff_image_removed { | |
106 | - img { | |
104 | + | |
105 | + &.diff_image_removed { | |
107 | 106 | border: 1px solid #C00; |
108 | 107 | } |
109 | - } | |
110 | 108 | |
111 | - &.diff_image_added { | |
112 | - img { | |
109 | + &.diff_image_added { | |
113 | 110 | border: 1px solid #0C0;; |
114 | 111 | } |
115 | 112 | } |
113 | + | |
114 | + &.img_compared { | |
115 | + img { | |
116 | + max-width:300px; | |
117 | + } | |
118 | + } | |
116 | 119 | } |
117 | 120 | } |
118 | 121 | ... | ... |
app/assets/stylesheets/sections/merge_requests.scss
... | ... | @@ -0,0 +1,96 @@ |
1 | +#tree-holder { | |
2 | + #tree-content-holder { | |
3 | + float:left; | |
4 | + width:100%; | |
5 | + } | |
6 | + #tree-readme-holder { | |
7 | + float:left; | |
8 | + width:100%; | |
9 | + .readme { | |
10 | + border:1px solid #ccc; | |
11 | + padding:12px; | |
12 | + background: #F7F7F7; | |
13 | + | |
14 | + pre { | |
15 | + overflow: auto; | |
16 | + } | |
17 | + } | |
18 | + } | |
19 | + | |
20 | + .tree_progress { | |
21 | + display:none; | |
22 | + margin:20px; | |
23 | + &.loading { | |
24 | + display:block; | |
25 | + } | |
26 | + } | |
27 | + | |
28 | + #tree-slider { | |
29 | + @include border-radius(0); | |
30 | + .tree-item { | |
31 | + &:hover { | |
32 | + td { background: $hover; } | |
33 | + cursor:pointer; | |
34 | + } | |
35 | + } | |
36 | + } | |
37 | + | |
38 | + .tree-item { | |
39 | + .tree-item-file-name { | |
40 | + vertical-align:middle; | |
41 | + font-weight:bold; | |
42 | + a { | |
43 | + color:$style_color; | |
44 | + &:hover { | |
45 | + color:$blue_link; | |
46 | + } | |
47 | + } | |
48 | + | |
49 | + img { | |
50 | + position: relative; | |
51 | + top:-1px; | |
52 | + } | |
53 | + } | |
54 | + } | |
55 | + | |
56 | + | |
57 | + #tree-slider { | |
58 | + @include solid_shade; | |
59 | + width:100%; | |
60 | + | |
61 | + border-color:#ccc; | |
62 | + | |
63 | + td { | |
64 | + padding:8px; | |
65 | + border-color:#f1f1f1; | |
66 | + background:#fafafa; | |
67 | + } | |
68 | + | |
69 | + tr:first-child td:first-child, | |
70 | + tr:first-child td:last-child { | |
71 | + border-radius:0; | |
72 | + } | |
73 | + | |
74 | + th { | |
75 | + border-color: #CCC; | |
76 | + border-bottom: 1px solid #bbb; | |
77 | + background:#eee; | |
78 | + background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); | |
79 | + background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); | |
80 | + background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); | |
81 | + background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); | |
82 | + } | |
83 | + } | |
84 | + | |
85 | + .tree-commit-link { | |
86 | + color:#333; | |
87 | + } | |
88 | + | |
89 | + a.tree-commit-link { | |
90 | + color: #666; | |
91 | + &:hover { | |
92 | + text-decoration: underline; | |
93 | + } | |
94 | + } | |
95 | + | |
96 | +} | ... | ... |
app/assets/stylesheets/themes/ui_mars.scss
app/assets/stylesheets/tree.scss
... | ... | @@ -1,232 +0,0 @@ |
1 | -#tree-holder { | |
2 | - #tree-content-holder { | |
3 | - float:left; | |
4 | - width:100%; | |
5 | - } | |
6 | - #tree-readme-holder { | |
7 | - float:left; | |
8 | - width:100%; | |
9 | - .readme { | |
10 | - border:1px solid #ccc; | |
11 | - padding:12px; | |
12 | - background: #F7F7F7; | |
13 | - | |
14 | - pre { | |
15 | - overflow: auto; | |
16 | - } | |
17 | - } | |
18 | - } | |
19 | - | |
20 | - .tree_progress { | |
21 | - display:none; | |
22 | - margin:20px; | |
23 | - &.loading { | |
24 | - display:block; | |
25 | - } | |
26 | - } | |
27 | - | |
28 | - | |
29 | - /** FILE CONTENT VIEW **/ | |
30 | - .view_file_content{ | |
31 | - .old_line, .new_line { | |
32 | - background:#ECECEC; | |
33 | - color:#777; | |
34 | - width:15px; | |
35 | - float:left; | |
36 | - padding: 0px 10px; | |
37 | - border-right: 1px solid #ccc; | |
38 | - } | |
39 | - .old_line{ | |
40 | - display:none; | |
41 | - } | |
42 | - } | |
43 | - | |
44 | - .view_file .view_file_header, | |
45 | - .diff_file .diff_file_header { | |
46 | - border-bottom: 1px solid #bbb; | |
47 | - background:#eee; | |
48 | - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); | |
49 | - background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); | |
50 | - background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); | |
51 | - background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); | |
52 | - margin: 0; | |
53 | - font-weight: normal; | |
54 | - font-weight: bold; | |
55 | - text-align: left; | |
56 | - color: #666; | |
57 | - padding: 9px 10px; | |
58 | - height:18px; | |
59 | - | |
60 | - .options { | |
61 | - float:right; | |
62 | - margin-top: -5px; | |
63 | - } | |
64 | - | |
65 | - .file_name { | |
66 | - color:$style_color; | |
67 | - font-size:14px; | |
68 | - text-shadow: 0 1px 1px #fff; | |
69 | - small { | |
70 | - color:#999; | |
71 | - font-size:13px; | |
72 | - } | |
73 | - } | |
74 | - } | |
75 | - | |
76 | - .view_file { | |
77 | - border:1px solid #CCC; | |
78 | - margin-bottom:1em; | |
79 | - | |
80 | - .view_file_content { | |
81 | - background:#fff; | |
82 | - color:#514721; | |
83 | - font-size: 11px; | |
84 | - } | |
85 | - .view_file_content_image { | |
86 | - background:#eee; | |
87 | - text-align:center; | |
88 | - img { | |
89 | - padding:100px; | |
90 | - max-width:300px; | |
91 | - } | |
92 | - } | |
93 | - } | |
94 | - | |
95 | - td.code { | |
96 | - width: 100%; | |
97 | - .highlight { | |
98 | - margin-left: 55px; | |
99 | - overflow:auto; | |
100 | - overflow-y:hidden; | |
101 | - } | |
102 | - } | |
103 | - .highlight pre { | |
104 | - white-space: pre; | |
105 | - word-wrap:normal; | |
106 | - } | |
107 | - | |
108 | - table.highlighttable { | |
109 | - border: none; | |
110 | - } | |
111 | - body.project-page table.highlighttable td { border: none } | |
112 | - table.highlighttable tr:hover { background:none;} | |
113 | - | |
114 | - table.highlighttable pre{ | |
115 | - line-height:16px !important; | |
116 | - font-size:12px !important; | |
117 | - } | |
118 | - | |
119 | - table.highlighttable .linenodiv pre { | |
120 | - text-align: right; | |
121 | - padding-right: 4px; | |
122 | - color:#666; | |
123 | - } | |
124 | - | |
125 | - #tree-slider { | |
126 | - @include border-radius(0); | |
127 | - .tree-item { | |
128 | - &:hover { | |
129 | - td { background: $hover; } | |
130 | - cursor:pointer; | |
131 | - } | |
132 | - } | |
133 | - } | |
134 | - | |
135 | - .tree-item { | |
136 | - .tree-item-file-name { | |
137 | - vertical-align:middle; | |
138 | - font-weight:bold; | |
139 | - a { | |
140 | - color:$style_color; | |
141 | - &:hover { | |
142 | - color:$blue_link; | |
143 | - } | |
144 | - } | |
145 | - | |
146 | - img { | |
147 | - position: relative; | |
148 | - top:-1px; | |
149 | - } | |
150 | - } | |
151 | - } | |
152 | - | |
153 | - | |
154 | - #tree-slider { | |
155 | - @include shade; | |
156 | - width:100%; | |
157 | - | |
158 | - border-color:#ccc; | |
159 | - | |
160 | - td { | |
161 | - padding:8px; | |
162 | - border-color:#f1f1f1; | |
163 | - background:#fafafa; | |
164 | - } | |
165 | - | |
166 | - tr:first-child td:first-child, | |
167 | - tr:first-child td:last-child { | |
168 | - border-radius:0; | |
169 | - } | |
170 | - | |
171 | - th { | |
172 | - border-color: #CCC; | |
173 | - border-bottom: 1px solid #bbb; | |
174 | - background:#eee; | |
175 | - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); | |
176 | - background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); | |
177 | - background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); | |
178 | - background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); | |
179 | - } | |
180 | - } | |
181 | - | |
182 | - .tree-commit-link { | |
183 | - color:#333; | |
184 | - } | |
185 | - | |
186 | - #tree-content-holder .view_file{ | |
187 | - @include shade; | |
188 | - } | |
189 | - | |
190 | - #tree-readme-holder .readme { | |
191 | - @include shade; | |
192 | - margin-bottom:20px; | |
193 | - h1, h2 { | |
194 | - line-height: 56px; | |
195 | - } | |
196 | - h3, h4 { | |
197 | - line-height: 46px; | |
198 | - } | |
199 | - } | |
200 | - | |
201 | - a.tree-commit-link { | |
202 | - color: #666; | |
203 | - &:hover { | |
204 | - text-decoration: underline; | |
205 | - } | |
206 | - } | |
207 | - | |
208 | -} | |
209 | - | |
210 | -.blame_file { | |
211 | - .view_file_content { | |
212 | - tr { | |
213 | - border-bottom: 1px solid #eee; | |
214 | - } | |
215 | - td { | |
216 | - padding:5px; | |
217 | - } | |
218 | - .author, | |
219 | - .commit { | |
220 | - background:#f5f5f5; | |
221 | - vertical-align:top; | |
222 | - } | |
223 | - .lines { | |
224 | - pre { | |
225 | - padding:0; | |
226 | - margin:0; | |
227 | - background:none; | |
228 | - border:none; | |
229 | - } | |
230 | - } | |
231 | - } | |
232 | -} |
... | ... | @@ -0,0 +1,26 @@ |
1 | +class CommitLoad < BaseContext | |
2 | + def execute | |
3 | + result = { | |
4 | + :commit => nil, | |
5 | + :suppress_diff => false, | |
6 | + :line_notes => [], | |
7 | + :notes_count => 0, | |
8 | + :note => nil | |
9 | + } | |
10 | + | |
11 | + commit = project.commit(params[:id]) | |
12 | + | |
13 | + if commit | |
14 | + commit = CommitDecorator.decorate(commit) | |
15 | + line_notes = project.commit_line_notes(commit) | |
16 | + | |
17 | + result[:suppress_diff] = true if commit.diffs.size > 200 && !params[:force_show_diff] | |
18 | + result[:commit] = commit | |
19 | + result[:note] = project.build_commit_note(commit) | |
20 | + result[:line_notes] = line_notes | |
21 | + result[:notes_count] = line_notes.count + project.commit_notes(commit).count | |
22 | + end | |
23 | + | |
24 | + result | |
25 | + end | |
26 | +end | ... | ... |
... | ... | @@ -0,0 +1,16 @@ |
1 | +class MergeRequestsLoad < BaseContext | |
2 | + def execute | |
3 | + type = params[:f].to_i | |
4 | + | |
5 | + merge_requests = project.merge_requests | |
6 | + | |
7 | + merge_requests = case type | |
8 | + when 1 then merge_requests | |
9 | + when 2 then merge_requests.closed | |
10 | + when 3 then merge_requests.opened.assigned(current_user) | |
11 | + else merge_requests.opened | |
12 | + end.page(params[:page]).per(20) | |
13 | + | |
14 | + merge_requests.includes(:author, :project).order("closed, created_at desc") | |
15 | + end | |
16 | +end | ... | ... |
... | ... | @@ -0,0 +1,30 @@ |
1 | +class NotesLoad < BaseContext | |
2 | + def execute | |
3 | + target_type = params[:target_type] | |
4 | + target_id = params[:target_id] | |
5 | + first_id = params[:first_id] | |
6 | + last_id = params[:last_id] | |
7 | + | |
8 | + | |
9 | + @notes = case target_type | |
10 | + when "commit" | |
11 | + then project.commit_notes(project.commit(target_id)).fresh.limit(20) | |
12 | + when "snippet" | |
13 | + then project.snippets.find(target_id).notes | |
14 | + when "wall" | |
15 | + then project.common_notes.order("created_at DESC").fresh.limit(50) | |
16 | + when "issue" | |
17 | + then project.issues.find(target_id).notes.inc_author.order("created_at DESC").limit(20) | |
18 | + when "merge_request" | |
19 | + then project.merge_requests.find(target_id).notes.inc_author.order("created_at DESC").limit(20) | |
20 | + end | |
21 | + | |
22 | + @notes = if last_id | |
23 | + @notes.where("id > ?", last_id) | |
24 | + elsif first_id | |
25 | + @notes.where("id < ?", first_id) | |
26 | + else | |
27 | + @notes | |
28 | + end | |
29 | + end | |
30 | +end | ... | ... |
... | ... | @@ -0,0 +1,44 @@ |
1 | +class Admin::HooksController < ApplicationController | |
2 | + layout "admin" | |
3 | + before_filter :authenticate_user! | |
4 | + before_filter :authenticate_admin! | |
5 | + | |
6 | + def index | |
7 | + @hooks = SystemHook.all | |
8 | + @hook = SystemHook.new | |
9 | + end | |
10 | + | |
11 | + def create | |
12 | + @hook = SystemHook.new(params[:hook]) | |
13 | + | |
14 | + if @hook.save | |
15 | + redirect_to admin_hooks_path, notice: 'Hook was successfully created.' | |
16 | + else | |
17 | + @hooks = SystemHook.all | |
18 | + render :index | |
19 | + end | |
20 | + end | |
21 | + | |
22 | + def destroy | |
23 | + @hook = SystemHook.find(params[:id]) | |
24 | + @hook.destroy | |
25 | + | |
26 | + redirect_to admin_hooks_path | |
27 | + end | |
28 | + | |
29 | + | |
30 | + def test | |
31 | + @hook = SystemHook.find(params[:hook_id]) | |
32 | + data = { | |
33 | + event_name: "project_create", | |
34 | + name: "Ruby", | |
35 | + path: "ruby", | |
36 | + project_id: 1, | |
37 | + owner_name: "Someone", | |
38 | + owner_email: "example@gitlabhq.com" | |
39 | + } | |
40 | + @hook.execute(data) | |
41 | + | |
42 | + redirect_to :back | |
43 | + end | |
44 | +end | ... | ... |
app/controllers/admin/mailer_controller.rb
... | ... | @@ -1,45 +0,0 @@ |
1 | -class Admin::MailerController < ApplicationController | |
2 | - layout "admin" | |
3 | - before_filter :authenticate_user! | |
4 | - before_filter :authenticate_admin! | |
5 | - | |
6 | - def preview | |
7 | - | |
8 | - end | |
9 | - | |
10 | - def preview_note | |
11 | - @note = Note.first | |
12 | - @user = @note.author | |
13 | - @project = @note.project | |
14 | - case params[:type] | |
15 | - when "Commit" then | |
16 | - @commit = @project.commit | |
17 | - render :file => 'notify/note_commit_email', :layout => 'notify' | |
18 | - when "Issue" then | |
19 | - @issue = Issue.first | |
20 | - render :file => 'notify/note_issue_email', :layout => 'notify' | |
21 | - else | |
22 | - render :file => 'notify/note_wall_email', :layout => 'notify' | |
23 | - end | |
24 | - rescue | |
25 | - render :text => "Preview not available" | |
26 | - end | |
27 | - | |
28 | - def preview_user_new | |
29 | - @user = User.first | |
30 | - @password = "DHasJKDHAS!" | |
31 | - | |
32 | - render :file => 'notify/new_user_email', :layout => 'notify' | |
33 | - rescue | |
34 | - render :text => "Preview not available" | |
35 | - end | |
36 | - | |
37 | - def preview_issue_new | |
38 | - @issue = Issue.first | |
39 | - @user = @issue.assignee | |
40 | - @project = @issue.project | |
41 | - render :file => 'notify/new_issue_email', :layout => 'notify' | |
42 | - rescue | |
43 | - render :text => "Preview not available" | |
44 | - end | |
45 | -end |
app/controllers/admin/projects_controller.rb
... | ... | @@ -6,7 +6,7 @@ class Admin::ProjectsController < ApplicationController |
6 | 6 | def index |
7 | 7 | @admin_projects = Project.scoped |
8 | 8 | @admin_projects = @admin_projects.search(params[:name]) if params[:name].present? |
9 | - @admin_projects = @admin_projects.page(params[:page]) | |
9 | + @admin_projects = @admin_projects.page(params[:page]).per(20) | |
10 | 10 | end |
11 | 11 | |
12 | 12 | def show |
... | ... | @@ -72,6 +72,6 @@ class Admin::ProjectsController < ApplicationController |
72 | 72 | @admin_project = Project.find_by_code(params[:id]) |
73 | 73 | @admin_project.destroy |
74 | 74 | |
75 | - redirect_to admin_projects_url | |
75 | + redirect_to admin_projects_url, notice: 'Project was successfully deleted.' | |
76 | 76 | end |
77 | 77 | end | ... | ... |
app/controllers/application_controller.rb
app/controllers/commits_controller.rb
... | ... | @@ -26,43 +26,31 @@ class CommitsController < ApplicationController |
26 | 26 | end |
27 | 27 | |
28 | 28 | def show |
29 | - @commit = project.commit(params[:id]) | |
30 | - | |
31 | - git_not_found! and return unless @commit | |
32 | - | |
33 | - @commit = CommitDecorator.decorate(@commit) | |
34 | - | |
35 | - @note = @project.build_commit_note(@commit) | |
36 | - @comments_allowed = true | |
37 | - @line_notes = project.commit_line_notes(@commit) | |
38 | - | |
39 | - @notes_count = @line_notes.count + project.commit_notes(@commit).count | |
40 | - | |
41 | - if @commit.diffs.size > 200 && !params[:force_show_diff] | |
42 | - @suppress_diff = true | |
29 | + result = CommitLoad.new(project, current_user, params).execute | |
30 | + | |
31 | + @commit = result[:commit] | |
32 | + | |
33 | + if @commit | |
34 | + @suppress_diff = result[:suppress_diff] | |
35 | + @note = result[:note] | |
36 | + @line_notes = result[:line_notes] | |
37 | + @notes_count = result[:notes_count] | |
38 | + @comments_allowed = true | |
39 | + else | |
40 | + return git_not_found! | |
43 | 41 | end |
42 | + | |
44 | 43 | rescue Grit::Git::GitTimeout |
45 | 44 | render "huge_commit" |
46 | 45 | end |
47 | 46 | |
48 | 47 | def compare |
49 | - first = project.commit(params[:to].try(:strip)) | |
50 | - last = project.commit(params[:from].try(:strip)) | |
48 | + result = Commit.compare(project, params[:from], params[:to]) | |
51 | 49 | |
52 | - @diffs = [] | |
53 | - @commits = [] | |
50 | + @commits = result[:commits] | |
51 | + @commit = result[:commit] | |
52 | + @diffs = result[:diffs] | |
54 | 53 | @line_notes = [] |
55 | - | |
56 | - if first && last | |
57 | - commits = [first, last].sort_by(&:created_at) | |
58 | - younger = commits.first | |
59 | - older = commits.last | |
60 | - | |
61 | - | |
62 | - @commits = project.repo.commits_between(younger.id, older.id).map {|c| Commit.new(c)} | |
63 | - @diffs = project.repo.diff(younger.id, older.id) rescue [] | |
64 | - @commit = Commit.new(older) | |
65 | - end | |
66 | 54 | end |
67 | 55 | |
68 | 56 | def patch | ... | ... |
app/controllers/dashboard_controller.rb
... | ... | @@ -2,15 +2,13 @@ class DashboardController < ApplicationController |
2 | 2 | respond_to :html |
3 | 3 | |
4 | 4 | def index |
5 | - @projects = current_user.projects.includes(:events).order("events.created_at DESC") | |
6 | - @projects = @projects.page(params[:page]).per(40) | |
7 | - | |
8 | - @events = Event.where(:project_id => current_user.projects.map(&:id)).recent.limit(20) | |
9 | - | |
5 | + @projects = current_user.projects_with_events.page(params[:page]).per(40) | |
6 | + @events = Event.recent_for_user(current_user).limit(20).offset(params[:offset] || 0) | |
10 | 7 | @last_push = current_user.recent_push |
11 | 8 | |
12 | 9 | respond_to do |format| |
13 | 10 | format.html |
11 | + format.js | |
14 | 12 | format.atom { render :layout => false } |
15 | 13 | end |
16 | 14 | end | ... | ... |
app/controllers/hooks_controller.rb
... | ... | @@ -11,24 +11,24 @@ class HooksController < ApplicationController |
11 | 11 | respond_to :html |
12 | 12 | |
13 | 13 | def index |
14 | - @hooks = @project.web_hooks.all | |
15 | - @hook = WebHook.new | |
14 | + @hooks = @project.hooks.all | |
15 | + @hook = ProjectHook.new | |
16 | 16 | end |
17 | 17 | |
18 | 18 | def create |
19 | - @hook = @project.web_hooks.new(params[:hook]) | |
19 | + @hook = @project.hooks.new(params[:hook]) | |
20 | 20 | @hook.save |
21 | 21 | |
22 | 22 | if @hook.valid? |
23 | 23 | redirect_to project_hooks_path(@project) |
24 | 24 | else |
25 | - @hooks = @project.web_hooks.all | |
25 | + @hooks = @project.hooks.all | |
26 | 26 | render :index |
27 | 27 | end |
28 | 28 | end |
29 | 29 | |
30 | 30 | def test |
31 | - @hook = @project.web_hooks.find(params[:id]) | |
31 | + @hook = @project.hooks.find(params[:id]) | |
32 | 32 | commits = @project.commits(@project.default_branch, nil, 3) |
33 | 33 | data = @project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{@project.default_branch}", current_user) |
34 | 34 | @hook.execute(data) |
... | ... | @@ -37,7 +37,7 @@ class HooksController < ApplicationController |
37 | 37 | end |
38 | 38 | |
39 | 39 | def destroy |
40 | - @hook = @project.web_hooks.find(params[:id]) | |
40 | + @hook = @project.hooks.find(params[:id]) | |
41 | 41 | @hook.destroy |
42 | 42 | |
43 | 43 | redirect_to project_hooks_path(@project) | ... | ... |
app/controllers/merge_requests_controller.rb
... | ... | @@ -24,16 +24,7 @@ class MergeRequestsController < ApplicationController |
24 | 24 | |
25 | 25 | |
26 | 26 | def index |
27 | - @merge_requests = @project.merge_requests | |
28 | - | |
29 | - @merge_requests = case params[:f].to_i | |
30 | - when 1 then @merge_requests | |
31 | - when 2 then @merge_requests.closed | |
32 | - when 3 then @merge_requests.opened.assigned(current_user) | |
33 | - else @merge_requests.opened | |
34 | - end.page(params[:page]).per(20) | |
35 | - | |
36 | - @merge_requests = @merge_requests.includes(:author, :project).order("closed, created_at desc") | |
27 | + @merge_requests = MergeRequestsLoad.new(project, current_user, params).execute | |
37 | 28 | end |
38 | 29 | |
39 | 30 | def show | ... | ... |
app/controllers/notes_controller.rb
... | ... | @@ -40,25 +40,6 @@ class NotesController < ApplicationController |
40 | 40 | protected |
41 | 41 | |
42 | 42 | def notes |
43 | - @notes = case params[:target_type] | |
44 | - when "commit" | |
45 | - then project.commit_notes(project.commit((params[:target_id]))).fresh.limit(20) | |
46 | - when "snippet" | |
47 | - then project.snippets.find(params[:target_id]).notes | |
48 | - when "wall" | |
49 | - then project.common_notes.order("created_at DESC").fresh.limit(50) | |
50 | - when "issue" | |
51 | - then project.issues.find(params[:target_id]).notes.inc_author.order("created_at DESC").limit(20) | |
52 | - when "merge_request" | |
53 | - then project.merge_requests.find(params[:target_id]).notes.inc_author.order("created_at DESC").limit(20) | |
54 | - end | |
55 | - | |
56 | - @notes = if params[:last_id] | |
57 | - @notes.where("id > ?", params[:last_id]) | |
58 | - elsif params[:first_id] | |
59 | - @notes.where("id < ?", params[:first_id]) | |
60 | - else | |
61 | - @notes | |
62 | - end | |
43 | + @notes = NotesLoad.new(project, current_user, params).execute | |
63 | 44 | end |
64 | 45 | end | ... | ... |
app/controllers/omniauth_callbacks_controller.rb
1 | 1 | class OmniauthCallbacksController < Devise::OmniauthCallbacksController |
2 | + | |
3 | + # Extend the standard message generation to accept our custom exception | |
4 | + def failure_message | |
5 | + exception = env["omniauth.error"] | |
6 | + if exception.class == OmniAuth::Error | |
7 | + error = exception.message | |
8 | + else | |
9 | + error = exception.error_reason if exception.respond_to?(:error_reason) | |
10 | + error ||= exception.error if exception.respond_to?(:error) | |
11 | + error ||= env["omniauth.error.type"].to_s | |
12 | + end | |
13 | + error.to_s.humanize if error | |
14 | + end | |
2 | 15 | |
3 | 16 | def ldap |
4 | 17 | # We only find ourselves here if the authentication to LDAP was successful. | ... | ... |
app/controllers/refs_controller.rb
... | ... | @@ -9,7 +9,7 @@ class RefsController < ApplicationController |
9 | 9 | before_filter :require_non_empty_project |
10 | 10 | |
11 | 11 | before_filter :ref |
12 | - before_filter :define_tree_vars, :only => [:tree, :blob, :blame] | |
12 | + before_filter :define_tree_vars, :only => [:tree, :blob, :blame, :logs_tree] | |
13 | 13 | before_filter :render_full_content |
14 | 14 | |
15 | 15 | layout "project" |
... | ... | @@ -46,6 +46,18 @@ class RefsController < ApplicationController |
46 | 46 | end |
47 | 47 | end |
48 | 48 | |
49 | + def logs_tree | |
50 | + contents = @tree.contents | |
51 | + @logs = contents.map do |content| | |
52 | + file = params[:path] ? File.join(params[:path], content.name) : content.name | |
53 | + last_commit = @project.commits(@commit.id, file, 1).last | |
54 | + { | |
55 | + :file_name => content.name, | |
56 | + :commit => last_commit | |
57 | + } | |
58 | + end | |
59 | + end | |
60 | + | |
49 | 61 | def blob |
50 | 62 | if @tree.is_blob? |
51 | 63 | if @tree.text? |
... | ... | @@ -79,6 +91,15 @@ class RefsController < ApplicationController |
79 | 91 | @commit = project.commit(@ref) |
80 | 92 | @tree = Tree.new(@commit.tree, project, @ref, params[:path]) |
81 | 93 | @tree = TreeDecorator.new(@tree) |
94 | + @hex_path = Digest::SHA1.hexdigest(params[:path] || "/") | |
95 | + | |
96 | + if params[:path] | |
97 | + @history_path = tree_file_project_ref_path(@project, @ref, params[:path]) | |
98 | + @logs_path = logs_file_project_ref_path(@project, @ref, params[:path]) | |
99 | + else | |
100 | + @history_path = tree_project_ref_path(@project, @ref) | |
101 | + @logs_path = logs_tree_project_ref_path(@project, @ref) | |
102 | + end | |
82 | 103 | rescue |
83 | 104 | return render_404 |
84 | 105 | end | ... | ... |
... | ... | @@ -0,0 +1,25 @@ |
1 | +class EventDecorator < ApplicationDecorator | |
2 | + decorates :event | |
3 | + | |
4 | + def feed_title | |
5 | + if self.issue? | |
6 | + "#{self.author_name} #{self.action_name} issue ##{self.target_id}:" + self.issue_title | |
7 | + elsif self.merge_request? | |
8 | + "#{self.author_name} #{self.action_name} MR ##{self.target_id}:" + self.merge_request_title | |
9 | + elsif self.push? | |
10 | + "#{self.author_name} #{self.push_action_name} #{self.ref_type} " + self.ref_name | |
11 | + else | |
12 | + "" | |
13 | + end | |
14 | + end | |
15 | + | |
16 | + def feed_url | |
17 | + if self.issue? | |
18 | + h.project_issue_url(self.project, self.issue) | |
19 | + elsif self.merge_request? | |
20 | + h.project_merge_request_url(self.project, self.merge_request) | |
21 | + elsif self.push? | |
22 | + h.project_commits_url(self.project, :ref => self.ref_name) | |
23 | + end | |
24 | + end | |
25 | +end | ... | ... |
app/helpers/application_helper.rb
... | ... | @@ -0,0 +1,27 @@ |
1 | +module TreeHelper | |
2 | + def tree_icon(content) | |
3 | + if content.is_a?(Grit::Blob) | |
4 | + if content.text? | |
5 | + image_tag "file_txt.png" | |
6 | + elsif content.image? | |
7 | + image_tag "file_img.png" | |
8 | + else | |
9 | + image_tag "file_bin.png" | |
10 | + end | |
11 | + else | |
12 | + image_tag "file_dir.png" | |
13 | + end | |
14 | + end | |
15 | + | |
16 | + def tree_hex_class(content) | |
17 | + "file_#{hexdigest(content.name)}" | |
18 | + end | |
19 | + | |
20 | + def tree_full_path(content) | |
21 | + if params[:path] | |
22 | + File.join(params[:path], content.name) | |
23 | + else | |
24 | + content.name | |
25 | + end | |
26 | + end | |
27 | +end | ... | ... |
app/models/commit.rb
... | ... | @@ -80,6 +80,29 @@ class Commit |
80 | 80 | def commits_between(repo, from, to) |
81 | 81 | repo.commits_between(from, to).map { |c| Commit.new(c) } |
82 | 82 | end |
83 | + | |
84 | + def compare(project, from, to) | |
85 | + first = project.commit(to.try(:strip)) | |
86 | + last = project.commit(from.try(:strip)) | |
87 | + | |
88 | + result = { | |
89 | + :commits => [], | |
90 | + :diffs => [], | |
91 | + :commit => nil | |
92 | + } | |
93 | + | |
94 | + if first && last | |
95 | + commits = [first, last].sort_by(&:created_at) | |
96 | + younger = commits.first | |
97 | + older = commits.last | |
98 | + | |
99 | + result[:commits] = project.repo.commits_between(younger.id, older.id).map {|c| Commit.new(c)} | |
100 | + result[:diffs] = project.repo.diff(younger.id, older.id) rescue [] | |
101 | + result[:commit] = Commit.new(older) | |
102 | + end | |
103 | + | |
104 | + result | |
105 | + end | |
83 | 106 | end |
84 | 107 | |
85 | 108 | def persisted? | ... | ... |
app/models/event.rb
app/models/merge_request.rb
... | ... | @@ -22,7 +22,6 @@ class MergeRequest < ActiveRecord::Base |
22 | 22 | :should_remove_source_branch |
23 | 23 | |
24 | 24 | validates_presence_of :project_id |
25 | - validates_presence_of :assignee_id | |
26 | 25 | validates_presence_of :author_id |
27 | 26 | validates_presence_of :source_branch |
28 | 27 | validates_presence_of :target_branch |
... | ... | @@ -36,6 +35,7 @@ class MergeRequest < ActiveRecord::Base |
36 | 35 | delegate :name, |
37 | 36 | :email, |
38 | 37 | :to => :assignee, |
38 | + :allow_nil => true, | |
39 | 39 | :prefix => true |
40 | 40 | |
41 | 41 | validates :title, |
... | ... | @@ -128,7 +128,7 @@ class MergeRequest < ActiveRecord::Base |
128 | 128 | |
129 | 129 | def unmerged_diffs |
130 | 130 | commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)} |
131 | - diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) | |
131 | + diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) rescue [] | |
132 | 132 | end |
133 | 133 | |
134 | 134 | def last_commit | ... | ... |
app/models/project.rb
... | ... | @@ -19,7 +19,7 @@ class Project < ActiveRecord::Base |
19 | 19 | has_many :notes, :dependent => :destroy |
20 | 20 | has_many :snippets, :dependent => :destroy |
21 | 21 | has_many :deploy_keys, :dependent => :destroy, :foreign_key => "project_id", :class_name => "Key" |
22 | - has_many :web_hooks, :dependent => :destroy | |
22 | + has_many :hooks, :dependent => :destroy, :class_name => "ProjectHook" | |
23 | 23 | has_many :wikis, :dependent => :destroy |
24 | 24 | has_many :protected_branches, :dependent => :destroy |
25 | 25 | |
... | ... | @@ -120,7 +120,7 @@ class Project < ActiveRecord::Base |
120 | 120 | errors.add(:path, " like 'gitolite-admin' is not allowed") |
121 | 121 | end |
122 | 122 | end |
123 | - | |
123 | + | |
124 | 124 | def self.access_options |
125 | 125 | UsersProject.access_roles |
126 | 126 | end | ... | ... |
app/models/user.rb
1 | 1 | class User < ActiveRecord::Base |
2 | + | |
2 | 3 | include Account |
3 | 4 | |
4 | - devise :database_authenticatable, :token_authenticatable, | |
5 | + devise :database_authenticatable, :token_authenticatable, :lockable, | |
5 | 6 | :recoverable, :rememberable, :trackable, :validatable, :omniauthable |
6 | 7 | |
7 | 8 | attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, |
8 | - :name, :projects_limit, :skype, :linkedin, :twitter, :dark_scheme, | |
9 | + :name, :projects_limit, :skype, :linkedin, :twitter, :dark_scheme, | |
9 | 10 | :theme_id, :force_random_password |
10 | 11 | |
11 | 12 | attr_accessor :force_random_password |
... | ... | @@ -15,6 +16,11 @@ class User < ActiveRecord::Base |
15 | 16 | has_many :my_own_projects, :class_name => "Project", :foreign_key => :owner_id |
16 | 17 | has_many :keys, :dependent => :destroy |
17 | 18 | |
19 | + has_many :events, | |
20 | + :class_name => "Event", | |
21 | + :foreign_key => :author_id, | |
22 | + :dependent => :destroy | |
23 | + | |
18 | 24 | has_many :recent_events, |
19 | 25 | :class_name => "Event", |
20 | 26 | :foreign_key => :author_id, |
... | ... | @@ -80,7 +86,8 @@ class User < ActiveRecord::Base |
80 | 86 | |
81 | 87 | def self.find_for_ldap_auth(omniauth_info) |
82 | 88 | name = omniauth_info.name.force_encoding("utf-8") |
83 | - email = omniauth_info.email.downcase | |
89 | + email = omniauth_info.email.downcase unless omniauth_info.email.nil? | |
90 | + raise OmniAuth::Error, "LDAP accounts must provide an email address" if email.nil? | |
84 | 91 | |
85 | 92 | if @user = User.find_by_email(email) |
86 | 93 | @user | ... | ... |
app/models/users_project.rb
app/models/web_hook.rb
... | ... | @@ -4,8 +4,6 @@ class WebHook < ActiveRecord::Base |
4 | 4 | # HTTParty timeout |
5 | 5 | default_timeout 10 |
6 | 6 | |
7 | - belongs_to :project | |
8 | - | |
9 | 7 | validates :url, |
10 | 8 | presence: true, |
11 | 9 | format: { |
... | ... | @@ -14,9 +12,8 @@ class WebHook < ActiveRecord::Base |
14 | 12 | |
15 | 13 | def execute(data) |
16 | 14 | WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" }) |
17 | - rescue | |
18 | - # There was a problem calling this web hook, let's forget about it. | |
19 | 15 | end |
16 | + | |
20 | 17 | end |
21 | 18 | # == Schema Information |
22 | 19 | # | ... | ... |
app/observers/mailer_observer.rb
... | ... | @@ -43,7 +43,7 @@ class MailerObserver < ActiveRecord::Observer |
43 | 43 | end |
44 | 44 | |
45 | 45 | def new_merge_request(merge_request) |
46 | - if merge_request.assignee != current_user | |
46 | + if merge_request.assignee && merge_request.assignee != current_user | |
47 | 47 | Notify.new_merge_request_email(merge_request.id).deliver |
48 | 48 | end |
49 | 49 | end | ... | ... |
... | ... | @@ -0,0 +1,67 @@ |
1 | +class SystemHookObserver < ActiveRecord::Observer | |
2 | + observe :user, :project, :users_project | |
3 | + | |
4 | + def after_create(model) | |
5 | + if model.kind_of? Project | |
6 | + SystemHook.all_hooks_fire({ | |
7 | + event_name: "project_create", | |
8 | + name: model.name, | |
9 | + path: model.path, | |
10 | + project_id: model.id, | |
11 | + owner_name: model.owner.name, | |
12 | + owner_email: model.owner.email, | |
13 | + created_at: model.created_at | |
14 | + }) | |
15 | + elsif model.kind_of? User | |
16 | + SystemHook.all_hooks_fire({ | |
17 | + event_name: "user_create", | |
18 | + name: model.name, | |
19 | + email: model.email, | |
20 | + created_at: model.created_at | |
21 | + }) | |
22 | + | |
23 | + elsif model.kind_of? UsersProject | |
24 | + SystemHook.all_hooks_fire({ | |
25 | + event_name: "user_add_to_team", | |
26 | + project_name: model.project.name, | |
27 | + project_path: model.project.path, | |
28 | + project_id: model.project_id, | |
29 | + user_name: model.user.name, | |
30 | + user_email: model.user.email, | |
31 | + project_access: model.repo_access_human, | |
32 | + created_at: model.created_at | |
33 | + }) | |
34 | + | |
35 | + end | |
36 | + end | |
37 | + | |
38 | + def after_destroy(model) | |
39 | + if model.kind_of? Project | |
40 | + SystemHook.all_hooks_fire({ | |
41 | + event_name: "project_destroy", | |
42 | + name: model.name, | |
43 | + path: model.path, | |
44 | + project_id: model.id, | |
45 | + owner_name: model.owner.name, | |
46 | + owner_email: model.owner.email, | |
47 | + }) | |
48 | + elsif model.kind_of? User | |
49 | + SystemHook.all_hooks_fire({ | |
50 | + event_name: "user_destroy", | |
51 | + name: model.name, | |
52 | + email: model.email | |
53 | + }) | |
54 | + | |
55 | + elsif model.kind_of? UsersProject | |
56 | + SystemHook.all_hooks_fire({ | |
57 | + event_name: "user_remove_from_team", | |
58 | + project_name: model.project.name, | |
59 | + project_path: model.project.path, | |
60 | + project_id: model.project_id, | |
61 | + user_name: model.user.name, | |
62 | + user_email: model.user.email, | |
63 | + project_access: model.repo_access_human | |
64 | + }) | |
65 | + end | |
66 | + end | |
67 | +end | ... | ... |
app/roles/account.rb
app/roles/git_push.rb
... | ... | @@ -27,7 +27,7 @@ module GitPush |
27 | 27 | true |
28 | 28 | end |
29 | 29 | |
30 | - def execute_web_hooks(oldrev, newrev, ref, user) | |
30 | + def execute_hooks(oldrev, newrev, ref, user) | |
31 | 31 | ref_parts = ref.split('/') |
32 | 32 | |
33 | 33 | # Return if this is not a push to a branch (e.g. new commits) |
... | ... | @@ -35,7 +35,7 @@ module GitPush |
35 | 35 | |
36 | 36 | data = post_receive_data(oldrev, newrev, ref, user) |
37 | 37 | |
38 | - web_hooks.each { |web_hook| web_hook.execute(data) } | |
38 | + hooks.each { |hook| hook.execute(data) } | |
39 | 39 | end |
40 | 40 | |
41 | 41 | def post_receive_data(oldrev, newrev, ref, user) |
... | ... | @@ -97,7 +97,7 @@ module GitPush |
97 | 97 | self.update_merge_requests(oldrev, newrev, ref, user) |
98 | 98 | |
99 | 99 | # Execute web hooks |
100 | - self.execute_web_hooks(oldrev, newrev, ref, user) | |
100 | + self.execute_hooks(oldrev, newrev, ref, user) | |
101 | 101 | |
102 | 102 | # Create satellite |
103 | 103 | self.satellite.create unless self.satellite.exists? | ... | ... |
... | ... | @@ -0,0 +1,66 @@ |
1 | +<% data_ex_str = <<eos | |
2 | +1. Project created: | |
3 | +{ | |
4 | + "created_at": "2012-07-21T07:30:54Z", | |
5 | + "event_name": "project_create", | |
6 | + "name": "StoreCloud", | |
7 | + "owner_email": "johnsmith@gmail.com", | |
8 | + "owner_name": "John Smith", | |
9 | + "path": "storecloud", | |
10 | + "project_id": 74 | |
11 | +} | |
12 | + | |
13 | +2. Project destroyed: | |
14 | +{ | |
15 | + "event_name": "project_destroy", | |
16 | + "name": "Underscore", | |
17 | + "owner_email": "johnsmith@gmail.com", | |
18 | + "owner_name": "John Smith", | |
19 | + "path": "underscore", | |
20 | + "project_id": 73 | |
21 | +} | |
22 | + | |
23 | +3. New Team Member: | |
24 | +{ | |
25 | + "created_at": "2012-07-21T07:30:56Z", | |
26 | + "event_name": "user_add_to_team", | |
27 | + "project_access": "Master", | |
28 | + "project_id": 74, | |
29 | + "project_name": "StoreCloud", | |
30 | + "project_path": "storecloud", | |
31 | + "owner_email": "johnsmith@gmail.com", | |
32 | + "owner_name": "John Smith", | |
33 | +} | |
34 | + | |
35 | +4. Team Member Removed: | |
36 | +{ | |
37 | + "created_at": "2012-07-21T07:30:56Z", | |
38 | + "event_name": "user_remove_from_team", | |
39 | + "project_access": "Master", | |
40 | + "project_id": 74, | |
41 | + "project_name": "StoreCloud", | |
42 | + "project_path": "storecloud", | |
43 | + "owner_email": "johnsmith@gmail.com", | |
44 | + "owner_name": "John Smith", | |
45 | +} | |
46 | + | |
47 | +5. User created: | |
48 | +{ | |
49 | + "created_at": "2012-07-21T07:44:07Z", | |
50 | + "email": "js@gitlabhq.com", | |
51 | + "event_name": "user_create", | |
52 | + "name": "John Smith" | |
53 | +} | |
54 | + | |
55 | +6. User removed: | |
56 | +{ | |
57 | + "created_at": "2012-07-21T07:44:07Z", | |
58 | + "email": "js@gitlabhq.com", | |
59 | + "event_name": "user_destroy", | |
60 | + "name": "John Smith" | |
61 | +} | |
62 | + | |
63 | +eos | |
64 | +%> | |
65 | +<% js_lexer = Pygments::Lexer[:js] %> | |
66 | +<%= raw js_lexer.highlight(data_ex_str) %> | ... | ... |
... | ... | @@ -0,0 +1,39 @@ |
1 | +.alert.alert-info | |
2 | + %span | |
3 | + Post receive hooks for binding events. | |
4 | + %br | |
5 | + Read more about system hooks | |
6 | + %strong #{link_to "here", help_system_hooks_path, :class => "vlink"} | |
7 | + | |
8 | += form_for @hook, :as => :hook, :url => admin_hooks_path do |f| | |
9 | + -if @hook.errors.any? | |
10 | + .alert-message.block-message.error | |
11 | + - @hook.errors.full_messages.each do |msg| | |
12 | + %p= msg | |
13 | + .clearfix | |
14 | + = f.label :url, "URL:" | |
15 | + .input | |
16 | + = f.text_field :url, :class => "text_field xxlarge" | |
17 | + | |
18 | + = f.submit "Add System Hook", :class => "btn primary" | |
19 | +%hr | |
20 | + | |
21 | +-if @hooks.any? | |
22 | + %h3 | |
23 | + Hooks | |
24 | + %small (#{@hooks.count}) | |
25 | + %br | |
26 | + %table.admin-table | |
27 | + %tr | |
28 | + %th URL | |
29 | + %th Method | |
30 | + %th | |
31 | + - @hooks.each do |hook| | |
32 | + %tr | |
33 | + %td | |
34 | + = link_to admin_hook_path(hook) do | |
35 | + %strong= hook.url | |
36 | + = link_to 'Test Hook', admin_hook_test_path(hook), :class => "btn small right" | |
37 | + %td POST | |
38 | + %td | |
39 | + = link_to 'Remove', admin_hook_path(hook), :confirm => 'Are you sure?', :method => :delete, :class => "danger btn small right" | ... | ... |
app/views/admin/logs/show.html.haml
1 | -%h4 | |
2 | - %i.icon-file | |
3 | - githost.log | |
4 | -%pre.logs | |
5 | - - Gitlab::Logger.read_latest.each do |line| | |
6 | - %span.log= line | |
1 | +.file_holder#README | |
2 | + .file_title | |
3 | + %i.icon-file | |
4 | + githost.log | |
5 | + .file_content.logs | |
6 | + %ol | |
7 | + - Gitlab::Logger.read_latest.each do |line| | |
8 | + %li | |
9 | + %p= line | ... | ... |
app/views/admin/mailer/preview.html.haml
... | ... | @@ -1,28 +0,0 @@ |
1 | -%p This is page with preview for all system emails that are sent to user | |
2 | -%p Email previews built based on existing Project/Commit/Issue base - so some preview maybe unavailable unless object appear in system | |
3 | - | |
4 | -#accordion | |
5 | - %h3 | |
6 | - %a New user | |
7 | - %div | |
8 | - %iframe{ :src=> admin_mailer_preview_user_new_path, :width=>"100%", :height=>"350"} | |
9 | - %h3 | |
10 | - %a New issue | |
11 | - %div | |
12 | - %iframe{ :src=> admin_mailer_preview_issue_new_path, :width=>"100%", :height=>"350"} | |
13 | - %h3 | |
14 | - %a Commit note | |
15 | - %div | |
16 | - %iframe{ :src=> admin_mailer_preview_note_path(:type => "Commit"), :width=>"100%", :height=>"350"} | |
17 | - %h3 | |
18 | - %a Issue note | |
19 | - %div | |
20 | - %iframe{ :src=> admin_mailer_preview_note_path(:type => "Issue"), :width=>"100%", :height=>"350"} | |
21 | - %h3 | |
22 | - %a Wall note | |
23 | - %div | |
24 | - %iframe{ :src=> admin_mailer_preview_note_path(:type => "Wall"), :width=>"100%", :height=>"350"} | |
25 | - | |
26 | -:javascript | |
27 | - $(function() { | |
28 | - $("#accordion").accordion(); }); |
app/views/admin/projects/index.html.haml
... | ... | @@ -13,8 +13,8 @@ |
13 | 13 | %th Team Members |
14 | 14 | %th Post Receive |
15 | 15 | %th Last Commit |
16 | - %th | |
17 | - %th | |
16 | + %th Edit | |
17 | + %th.cred Danger Zone! | |
18 | 18 | |
19 | 19 | - @admin_projects.each do |project| |
20 | 20 | %tr |
... | ... | @@ -24,5 +24,5 @@ |
24 | 24 | %td= check_box_tag :post_receive_file, 1, project.has_post_receive_file?, :disabled => true |
25 | 25 | %td= last_commit(project) |
26 | 26 | %td= link_to 'Edit', edit_admin_project_path(project), :id => "edit_#{dom_id(project)}", :class => "btn small" |
27 | - %td= link_to 'Destroy', [:admin, project], :confirm => 'Are you sure?', :method => :delete, :class => "btn small danger" | |
27 | + %td.bgred= link_to 'Destroy', [:admin, project], :confirm => "REMOVE #{project.name}? Are you sure?", :method => :delete, :class => "btn small danger" | |
28 | 28 | = paginate @admin_projects, :theme => "admin" | ... | ... |
app/views/admin/users/_form.html.haml
... | ... | @@ -50,7 +50,7 @@ |
50 | 50 | |
51 | 51 | .alert |
52 | 52 | .clearfix |
53 | - %p Give user ability to manage application. | |
53 | + %p Make the user a GitLab administrator. | |
54 | 54 | = f.label :admin, :class => "checkbox" do |
55 | 55 | = f.check_box :admin |
56 | 56 | %span Administrator |
... | ... | @@ -59,11 +59,11 @@ |
59 | 59 | - if @admin_user.blocked |
60 | 60 | %span |
61 | 61 | = link_to 'Unblock', unblock_admin_user_path(@admin_user), :method => :put, :class => "btn small" |
62 | - This user is blocked and is not able to login GitLab | |
62 | + This user is blocked and is not able to login to GitLab | |
63 | 63 | - else |
64 | 64 | %span |
65 | 65 | = link_to 'Block', block_admin_user_path(@admin_user), :confirm => 'USER WILL BE BLOCKED! Are you sure?', :method => :put, :class => "btn small danger" |
66 | - Blocked user will removed from all projects & will not be able to login to GitLab. | |
66 | + Blocked users will be removed from all projects & will not be able to login to GitLab. | |
67 | 67 | .actions |
68 | 68 | = f.submit 'Save', :class => "btn primary" |
69 | 69 | - if @admin_user.new_record? | ... | ... |
app/views/admin/users/index.html.haml
... | ... | @@ -27,7 +27,7 @@ |
27 | 27 | %th Projects |
28 | 28 | %th Edit |
29 | 29 | %th Blocked |
30 | - %th | |
30 | + %th.cred Danger Zone! | |
31 | 31 | |
32 | 32 | - @admin_users.each do |user| |
33 | 33 | %tr |
... | ... | @@ -41,6 +41,6 @@ |
41 | 41 | = link_to 'Unblock', unblock_admin_user_path(user), :method => :put, :class => "btn small success" |
42 | 42 | - else |
43 | 43 | = link_to 'Block', block_admin_user_path(user), :confirm => 'USER WILL BE BLOCKED! Are you sure?', :method => :put, :class => "btn small danger" |
44 | - %td= link_to 'Destroy', [:admin, user], :confirm => 'USER WILL BE REMOVED! Are you sure?', :method => :delete, :class => "btn small danger" | |
44 | + %td.bgred= link_to 'Destroy', [:admin, user], :confirm => "USER #{user.name} WILL BE REMOVED! Are you sure?", :method => :delete, :class => "btn small danger" | |
45 | 45 | |
46 | 46 | = paginate @admin_users, :theme => "admin" | ... | ... |
app/views/commits/_commits.html.haml
app/views/commits/_diffs.html.haml
... | ... | @@ -35,7 +35,13 @@ |
35 | 35 | - if file.text? |
36 | 36 | = render "commits/text_file", :diff => diff, :index => i |
37 | 37 | - elsif file.image? |
38 | - .diff_file_content_image{:class => image_diff_class(diff)} | |
39 | - %img{:src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} | |
38 | + - if diff.renamed_file || diff.new_file || diff.deleted_file | |
39 | + .diff_file_content_image | |
40 | + %img{:class => image_diff_class(diff), :src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} | |
41 | + - else | |
42 | + - old_file = (@commit.prev_commit.tree / diff.old_path) | |
43 | + .diff_file_content_image.img_compared | |
44 | + %img{:class => "diff_image_removed", :src => "data:#{file.mime_type};base64,#{Base64.encode64(old_file.data)}"} | |
45 | + %img{:class => "diff_image_added", :src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} | |
40 | 46 | - else |
41 | 47 | %p.nothing_here_message No preview for this file type | ... | ... |
app/views/commits/_head.html.haml
... | ... | @@ -13,12 +13,12 @@ |
13 | 13 | %li{:class => "#{branches_tab_class}"} |
14 | 14 | = link_to project_repository_path(@project) do |
15 | 15 | Branches |
16 | - %span.number= @project.repo.branch_count | |
16 | + %span.badge= @project.repo.branch_count | |
17 | 17 | |
18 | 18 | %li{:class => "#{'active' if current_page?(tags_project_repository_path(@project)) }"} |
19 | 19 | = link_to tags_project_repository_path(@project) do |
20 | 20 | Tags |
21 | - %span.number= @project.repo.tag_count | |
21 | + %span.badge= @project.repo.tag_count | |
22 | 22 | |
23 | 23 | |
24 | 24 | - if current_page?(project_commits_path(@project)) && current_user.private_token | ... | ... |
app/views/commits/compare.html.haml
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | = "..." |
21 | 21 | = text_field_tag :to, params[:to], :placeholder => "aa8b4ef", :class => "xlarge" |
22 | 22 | .actions |
23 | - = submit_tag "Compare", :class => "btn primary" | |
23 | + = submit_tag "Compare", :class => "btn btn-primary" | |
24 | 24 | |
25 | 25 | |
26 | 26 | - unless @commits.empty? | ... | ... |
app/views/dashboard/index.atom.builder
... | ... | @@ -8,17 +8,10 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear |
8 | 8 | |
9 | 9 | @events.each do |event| |
10 | 10 | if event.allowed? |
11 | + event = EventDecorator.decorate(event) | |
11 | 12 | xml.entry do |
12 | - if event.issue? | |
13 | - event_link = project_issue_url(event.project, event.issue) | |
14 | - event_title = event.issue_title | |
15 | - elsif event.merge_request? | |
16 | - event_link = project_merge_request_url(event.project, event.merge_request) | |
17 | - event_title = event.merge_request_title | |
18 | - elsif event.push? | |
19 | - event_link = project_commits_url(event.project, :ref => event.ref_name) | |
20 | - event_title = event.ref_name | |
21 | - end | |
13 | + event_link = event.feed_url | |
14 | + event_title = event.feed_title | |
22 | 15 | |
23 | 16 | xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}" |
24 | 17 | xml.link :href => event_link | ... | ... |
app/views/dashboard/index.html.haml
... | ... | @@ -10,9 +10,10 @@ |
10 | 10 | add new key |
11 | 11 | to your profile |
12 | 12 | - if @events.any? |
13 | - = render @events | |
13 | + .content_list= render @events | |
14 | 14 | - else |
15 | 15 | %h4.nothing_here_message Projects activity will be displayed here |
16 | + .loading.hide | |
16 | 17 | .side |
17 | 18 | = render "events/event_last_push", :event => @last_push |
18 | 19 | .projects_box |
... | ... | @@ -54,3 +55,7 @@ |
54 | 55 | New Project » |
55 | 56 | - else |
56 | 57 | If you will be added to project - it will be displayed here |
58 | + | |
59 | + | |
60 | +:javascript | |
61 | + $(function(){ Pager.init(20); }); | ... | ... |
app/views/dashboard/index.js.haml
app/views/events/_event_issue.html.haml
1 | 1 | = image_tag gravatar_icon(event.author_email), :class => "avatar" |
2 | 2 | %strong #{event.author_name} |
3 | -%span.event_label= event.action_name | |
4 | - issue | |
3 | +%span.event_label{:class => event.action_name}= event.action_name | |
4 | +issue | |
5 | 5 | = link_to project_issue_path(event.project, event.issue) do |
6 | 6 | %strong= truncate event.issue_title |
7 | 7 | at | ... | ... |
app/views/events/_event_last_push.html.haml
... | ... | @@ -5,12 +5,9 @@ |
5 | 5 | %span Your pushed to |
6 | 6 | = event.ref_type |
7 | 7 | = link_to project_commits_path(event.project, :ref => event.ref_name) do |
8 | - %strong= event.ref_name | |
8 | + %strong= truncate(event.ref_name, :length => 28) | |
9 | 9 | at |
10 | 10 | %strong= link_to event.project.name, event.project |
11 | - %span.cgray | |
12 | - = time_ago_in_words(event.created_at) | |
13 | - ago. | |
14 | 11 | |
15 | 12 | = link_to new_mr_path_from_push_event(event), :title => "New Merge Request", :class => "btn very_small primary" do |
16 | 13 | Create Merge Request | ... | ... |
app/views/events/_event_merge_request.html.haml
... | ... | @@ -2,8 +2,8 @@ |
2 | 2 | .event_icon= image_tag "event_mr_merged.png" |
3 | 3 | = image_tag gravatar_icon(event.author_email), :class => "avatar" |
4 | 4 | %strong #{event.author_name} |
5 | -%span.event_label= event.action_name | |
6 | - merge request | |
5 | +%span.event_label{:class => event.action_name}= event.action_name | |
6 | +merge request | |
7 | 7 | = link_to project_merge_request_path(event.project, event.merge_request) do |
8 | 8 | %strong= truncate event.merge_request_title |
9 | 9 | at | ... | ... |
app/views/events/_event_push.html.haml
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | .event_icon= image_tag "event_push.png" |
3 | 3 | = image_tag gravatar_icon(event.author_email), :class => "avatar" |
4 | 4 | %strong #{event.author_name} |
5 | - %span.event_label= event.push_action_name | |
5 | + %span.event_label.pushed= event.push_action_name | |
6 | 6 | = event.ref_type |
7 | 7 | = link_to project_commits_path(event.project, :ref => event.ref_name) do |
8 | 8 | %strong= event.ref_name | ... | ... |
... | ... | @@ -0,0 +1,41 @@ |
1 | +%h3 API | |
2 | +.back_link | |
3 | + = link_to help_path do | |
4 | + ← to index | |
5 | +%hr | |
6 | + | |
7 | +%ol | |
8 | + %li | |
9 | + %a{:href => "#README"} README | |
10 | + %li | |
11 | + %a{:href => "#projects"} Projects | |
12 | + %li | |
13 | + %a{:href => "#users"} Users | |
14 | + | |
15 | +.file_holder#README | |
16 | + .file_title | |
17 | + %i.icon-file | |
18 | + README | |
19 | + .file_content.wiki | |
20 | + = preserve do | |
21 | + = markdown File.read(Rails.root.join("doc", "api", "README.md")) | |
22 | + | |
23 | +%br | |
24 | + | |
25 | +.file_holder#projects | |
26 | + .file_title | |
27 | + %i.icon-file | |
28 | + Projects | |
29 | + .file_content.wiki | |
30 | + = preserve do | |
31 | + = markdown File.read(Rails.root.join("doc", "api", "projects.md")) | |
32 | + | |
33 | +%br | |
34 | + | |
35 | +.file_holder#users | |
36 | + .file_title | |
37 | + %i.icon-file | |
38 | + Users | |
39 | + .file_content.wiki | |
40 | + = preserve do | |
41 | + = markdown File.read(Rails.root.join("doc", "api", "users.md")) | ... | ... |
app/views/help/index.html.haml
... | ... | @@ -0,0 +1,13 @@ |
1 | +%h3 System hooks | |
2 | +.back_link | |
3 | + = link_to :back do | |
4 | + ← back | |
5 | +%hr | |
6 | + | |
7 | +%p.slead | |
8 | + Your Gitlab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member. | |
9 | + %br | |
10 | + System Hooks can be used for logging or change information in LDAP server. | |
11 | + %br | |
12 | +%h5 Hooks request example: | |
13 | += render "admin/hooks/data_ex" | ... | ... |
app/views/issues/_issues.html.haml
... | ... | @@ -6,7 +6,9 @@ |
6 | 6 | .row |
7 | 7 | .span7= paginate @issues, :remote => true, :theme => "gitlab" |
8 | 8 | .span3.right |
9 | - %span.cgray.right #{@issues.total_count} issues for this filter | |
9 | + %span.cgray.right | |
10 | + %span.issue_counter #{@issues.total_count} | |
11 | + issues for this filter | |
10 | 12 | - else |
11 | 13 | %li |
12 | 14 | %h4.nothing_here_message Nothing to show here | ... | ... |
app/views/issues/_show.html.haml
... | ... | @@ -12,9 +12,9 @@ |
12 | 12 | = issue.notes.count |
13 | 13 | - if can? current_user, :modify_issue, issue |
14 | 14 | - if issue.closed |
15 | - = link_to 'Reopen', project_issue_path(issue.project, issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "btn small grouped", :remote => true | |
15 | + = link_to 'Reopen', project_issue_path(issue.project, issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "btn small grouped reopen_issue", :remote => true | |
16 | 16 | - else |
17 | - = link_to 'Resolve', project_issue_path(issue.project, issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "success btn small grouped", :remote => true | |
17 | + = link_to 'Resolve', project_issue_path(issue.project, issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "success btn small grouped close_issue", :remote => true | |
18 | 18 | = link_to edit_project_issue_path(issue.project, issue), :class => "btn small edit-issue-link", :remote => true do |
19 | 19 | %i.icon-edit |
20 | 20 | Edit |
... | ... | @@ -35,6 +35,4 @@ |
35 | 35 | |
36 | 36 | |
37 | 37 | - if issue.upvotes > 0 |
38 | - %span.badge.badge-success= "+#{issue.upvotes}" | |
39 | - | |
40 | - | |
38 | + %span.badge.badge-success= "+#{issue.upvotes}" | |
41 | 39 | \ No newline at end of file | ... | ... |
app/views/issues/index.html.haml
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | .issues_content |
3 | 3 | %h3.page_title |
4 | 4 | Issues |
5 | - %small (#{@issues.total_count}) | |
5 | + %small (<span class=issue_counter>#{@issues.total_count}</span>) | |
6 | 6 | .right |
7 | 7 | .span5 |
8 | 8 | - if can? current_user, :write_issue, @project |
... | ... | @@ -45,4 +45,4 @@ |
45 | 45 | :javascript |
46 | 46 | $(function(){ |
47 | 47 | issuesPage(); |
48 | 48 | - }) |
49 | + }) | |
49 | 50 | \ No newline at end of file | ... | ... |
app/views/keys/new.html.haml
app/views/layouts/_project_menu.html.haml
... | ... | @@ -17,14 +17,14 @@ |
17 | 17 | %li{:class => tab_class(:issues)} |
18 | 18 | = link_to project_issues_filter_path(@project) do |
19 | 19 | Issues |
20 | - %span.count= @project.issues.opened.count | |
20 | + %span.count.issue_counter= @project.issues.opened.count | |
21 | 21 | |
22 | 22 | - if @project.repo_exists? |
23 | 23 | - if @project.merge_requests_enabled |
24 | 24 | %li{:class => tab_class(:merge_requests)} |
25 | 25 | = link_to project_merge_requests_path(@project) do |
26 | 26 | Merge Requests |
27 | - %span.count= @project.merge_requests.opened.count | |
27 | + %span.count.merge_counter= @project.merge_requests.opened.count | |
28 | 28 | |
29 | 29 | - if @project.wall_enabled |
30 | 30 | %li{:class => tab_class(:wall)} | ... | ... |
app/views/layouts/admin.html.haml
... | ... | @@ -15,7 +15,7 @@ |
15 | 15 | %li{:class => tab_class(:admin_logs)} |
16 | 16 | = link_to "Logs", admin_logs_path |
17 | 17 | %li{:class => tab_class(:admin_emails)} |
18 | - = link_to "Emails", admin_emails_path | |
18 | + = link_to "Hooks", admin_hooks_path | |
19 | 19 | %li{:class => tab_class(:admin_resque)} |
20 | 20 | = link_to "Resque", admin_resque_path |
21 | 21 | ... | ... |
app/views/layouts/devise.html.haml
app/views/layouts/profile.html.haml
... | ... | @@ -12,16 +12,17 @@ |
12 | 12 | %li{:class => tab_class(:password)} |
13 | 13 | = link_to "Password", profile_password_path |
14 | 14 | |
15 | + %li{:class => tab_class(:ssh_keys)} | |
16 | + = link_to keys_path do | |
17 | + SSH Keys | |
18 | + %span.count= current_user.keys.count | |
19 | + | |
15 | 20 | %li{:class => tab_class(:token)} |
16 | 21 | = link_to "Token", profile_token_path |
17 | 22 | |
18 | 23 | %li{:class => tab_class(:design)} |
19 | 24 | = link_to "Design", profile_design_path |
20 | 25 | |
21 | - %li{:class => tab_class(:ssh_keys)} | |
22 | - = link_to keys_path do | |
23 | - SSH Keys | |
24 | - %span.count= current_user.keys.count | |
25 | 26 | |
26 | 27 | .content |
27 | 28 | = yield | ... | ... |
app/views/merge_requests/_form.html.haml
... | ... | @@ -5,7 +5,8 @@ |
5 | 5 | - @merge_request.errors.full_messages.each do |msg| |
6 | 6 | %li= msg |
7 | 7 | |
8 | - %h3.padded.cgray 1. Select Branches | |
8 | + %h4.cdark 1. Select Branches | |
9 | + %br | |
9 | 10 | |
10 | 11 | .row |
11 | 12 | .span6 |
... | ... | @@ -30,14 +31,21 @@ |
30 | 31 | .bottom_commit |
31 | 32 | .mr_target_commit |
32 | 33 | |
33 | - %h3.padded.cgray 2. Fill info | |
34 | + %h4.cdark 2. Fill info | |
35 | + | |
34 | 36 | .clearfix |
35 | - = f.label :assignee_id, "Assign to", :class => "control-label" | |
36 | - .controls= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" }, :style => "width:250px") | |
37 | + .main_box | |
38 | + .top_box_content | |
39 | + = f.label :title do | |
40 | + %strong= "Title *" | |
41 | + .input= f.text_field :title, :class => "input-xxlarge pad", :maxlength => 255, :rows => 5 | |
42 | + .middle_box_content | |
43 | + = f.label :assignee_id do | |
44 | + %i.icon-user | |
45 | + Assign to | |
46 | + .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" }, :style => "width:250px") | |
37 | 47 | |
38 | 48 | .control-group |
39 | - = f.label :title, :class => "control-label" | |
40 | - .controls= f.text_field :title, :class => "input-xxlarge pad", :maxlength => 255, :rows => 5 | |
41 | 49 | |
42 | 50 | .form-actions |
43 | 51 | = f.submit 'Save', :class => "btn-primary btn" | ... | ... |
app/views/merge_requests/_merge_request.html.haml
... | ... | @@ -15,12 +15,14 @@ |
15 | 15 | → |
16 | 16 | = merge_request.target_branch |
17 | 17 | = image_tag gravatar_icon(merge_request.author_email), :class => "avatar" |
18 | + | |
19 | + = link_to project_merge_request_path(merge_request.project, merge_request) do | |
20 | + %p.row_title= truncate(merge_request.title, :length => 80) | |
21 | + | |
18 | 22 | %span.update-author |
19 | - %strong= merge_request.author_name | |
20 | - authored | |
23 | + %small.cdark= "##{merge_request.id}" | |
24 | + authored by #{merge_request.author_name} | |
21 | 25 | = time_ago_in_words(merge_request.created_at) |
22 | 26 | ago |
23 | 27 | - if merge_request.upvotes > 0 |
24 | 28 | %span.badge.badge-success= "+#{merge_request.upvotes}" |
25 | - = link_to project_merge_request_path(merge_request.project, merge_request) do | |
26 | - %p.row_title= truncate(merge_request.title, :length => 80) | ... | ... |
app/views/merge_requests/edit.html.haml
app/views/merge_requests/new.html.haml
app/views/merge_requests/show/_commits.html.haml
app/views/merge_requests/show/_mr_box.html.haml
... | ... | @@ -13,9 +13,10 @@ |
13 | 13 | = image_tag gravatar_icon(@merge_request.author_email), :width => 16, :class => "lil_av" |
14 | 14 | %strong.author= link_to_merge_request_author(@merge_request) |
15 | 15 | |
16 | - %cite.cgray and currently assigned to | |
17 | - = image_tag gravatar_icon(@merge_request.assignee_email), :width => 16, :class => "lil_av" | |
18 | - %strong.author= link_to_merge_request_assignee(@merge_request) | |
16 | + - if @merge_request.assignee | |
17 | + %cite.cgray and currently assigned to | |
18 | + = image_tag gravatar_icon(@merge_request.assignee_email), :width => 16, :class => "lil_av" | |
19 | + %strong.author= link_to_merge_request_assignee(@merge_request) | |
19 | 20 | |
20 | 21 | |
21 | 22 | - if @merge_request.closed | ... | ... |
app/views/notes/_form.html.haml
app/views/notes/_per_line_form.html.haml
... | ... | @@ -24,7 +24,7 @@ |
24 | 24 | = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit" |
25 | 25 | %span Commit author |
26 | 26 | .actions |
27 | - = f.submit 'Add note', :class => "btn primary", :id => "submit_note" | |
27 | + = f.submit 'Add note', :class => "btn primary submit_note", :id => "submit_note" | |
28 | 28 | = link_to "Close", "#", :class => "btn hide-button" |
29 | 29 | |
30 | 30 | :javascript | ... | ... |
app/views/notes/_reply_button.html.haml
app/views/refs/_tree.html.haml
... | ... | @@ -13,7 +13,7 @@ |
13 | 13 | = render :partial => "refs/tree_file", :locals => { :name => tree.name, :content => tree.data, :file => tree } |
14 | 14 | - else |
15 | 15 | - contents = tree.contents |
16 | - %table#tree-slider.bordered-table.table | |
16 | + %table#tree-slider.bordered-table.table{:class => "table_#{@hex_path}" } | |
17 | 17 | %thead |
18 | 18 | %th Name |
19 | 19 | %th Last Update |
... | ... | @@ -29,34 +29,39 @@ |
29 | 29 | %td |
30 | 30 | %td |
31 | 31 | |
32 | + - index = 0 | |
32 | 33 | - contents.select{ |i| i.is_a?(Grit::Tree)}.each do |content| |
33 | - = render :partial => "refs/tree_item", :locals => { :content => content } | |
34 | + = render :partial => "refs/tree_item", :locals => { :content => content, :index => (index += 1) } | |
34 | 35 | - contents.select{ |i| i.is_a?(Grit::Blob)}.each do |content| |
35 | - = render :partial => "refs/tree_item", :locals => { :content => content } | |
36 | + = render :partial => "refs/tree_item", :locals => { :content => content, :index => (index += 1) } | |
36 | 37 | - contents.select{ |i| i.is_a?(Grit::Submodule)}.each do |content| |
37 | - = render :partial => "refs/submodule_item", :locals => { :content => content } | |
38 | + = render :partial => "refs/submodule_item", :locals => { :content => content, :index => (index += 1) } | |
38 | 39 | |
39 | 40 | - if content = contents.select{ |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i }.first |
40 | - #tree-readme-holder | |
41 | - %h3= content.name | |
42 | - .readme | |
41 | + .file_holder#README | |
42 | + .file_title | |
43 | + %i.icon-file | |
44 | + = content.name | |
45 | + .file_content.wiki | |
43 | 46 | - if content.name =~ /\.(md|markdown)$/i |
44 | 47 | = preserve do |
45 | 48 | = markdown(content.data) |
46 | 49 | - else |
47 | 50 | = simple_format(content.data) |
48 | 51 | |
49 | -- if params[:path] | |
50 | - - history_path = tree_file_project_ref_path(@project, @ref, params[:path]) | |
51 | -- else | |
52 | - - history_path = tree_project_ref_path(@project, @ref) | |
53 | 52 | :javascript |
54 | 53 | $(function(){ |
55 | 54 | $('select#branch').selectmenu({style:'popup', width:200}); |
56 | 55 | $('select#tag').selectmenu({style:'popup', width:200}); |
57 | 56 | $('.project-refs-select').chosen(); |
58 | 57 | |
59 | - history.pushState({ path: this.path }, '', "#{history_path}") | |
58 | + history.pushState({ path: this.path }, '', "#{@history_path}"); | |
59 | + | |
60 | + }); | |
61 | + | |
62 | + // Load last commit log for each file in tree | |
63 | + $(window).load(function(){ | |
64 | + ajaxGet('#{@logs_path}'); | |
60 | 65 | }); |
61 | 66 | |
62 | 67 | ... | ... |
app/views/refs/_tree_file.html.haml
1 | -.view_file | |
2 | - .view_file_header | |
1 | +.file_holder | |
2 | + .file_title | |
3 | 3 | %i.icon-file |
4 | 4 | %span.file_name |
5 | 5 | = name |
... | ... | @@ -10,26 +10,28 @@ |
10 | 10 | = link_to "blame", blame_file_project_ref_path(@project, @ref, :path => params[:path]), :class => "btn very_small" |
11 | 11 | - if file.text? |
12 | 12 | - if name =~ /\.(md|markdown)$/i |
13 | - #tree-readme-holder | |
14 | - .readme | |
15 | - = preserve do | |
16 | - = markdown(file.data) | |
13 | + .file_content.wiki | |
14 | + = preserve do | |
15 | + = markdown(file.data) | |
17 | 16 | - else |
18 | - .view_file_content | |
17 | + .file_content.code | |
19 | 18 | - unless file.empty? |
20 | 19 | %div{:class => current_user.dark_scheme ? "black" : "white"} |
21 | 20 | = preserve do |
22 | 21 | = raw file.colorize(options: { linenos: 'True'}) |
23 | 22 | - else |
24 | 23 | %h4.nothing_here_message Empty file |
24 | + | |
25 | 25 | - elsif file.image? |
26 | - .view_file_content_image | |
26 | + .file_content.image_file | |
27 | 27 | %img{ :src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} |
28 | + | |
28 | 29 | - else |
29 | - %center | |
30 | - = link_to blob_project_ref_path(@project, @ref, :path => params[:path]) do | |
31 | - %div.padded | |
32 | - %br | |
33 | - = image_tag "download.png", :width => 64 | |
34 | - %h3 | |
35 | - Download (#{file.mb_size}) | |
30 | + .file_content.blob_file | |
31 | + %center | |
32 | + = link_to blob_project_ref_path(@project, @ref, :path => params[:path]) do | |
33 | + %div.padded | |
34 | + %br | |
35 | + = image_tag "download.png", :width => 64 | |
36 | + %h3 | |
37 | + Download (#{file.mb_size}) | ... | ... |
app/views/refs/_tree_item.html.haml
1 | -- file = params[:path] ? File.join(params[:path], content.name) : content.name | |
2 | -- content_commit = @project.commits(@commit.id, file, 1).last | |
3 | -- return unless content_commit | |
4 | -%tr{ :class => "tree-item", :url => tree_file_project_ref_path(@project, @ref, file) } | |
1 | +- file = tree_full_path(content) | |
2 | +%tr{ :class => "tree-item #{tree_hex_class(content)}", :url => tree_file_project_ref_path(@project, @ref, file) } | |
5 | 3 | %td.tree-item-file-name |
6 | - - if content.is_a?(Grit::Blob) | |
7 | - - if content.text? | |
8 | - = image_tag "file_txt.png" | |
9 | - - elsif content.image? | |
10 | - = image_tag "file_img.png" | |
11 | - - else | |
12 | - = image_tag "file_bin.png" | |
13 | - - else | |
14 | - = image_tag "file_dir.png" | |
4 | + = tree_icon(content) | |
15 | 5 | = link_to truncate(content.name, :length => 40), tree_file_project_ref_path(@project, @ref || @commit.id, file), :remote => :true |
16 | - %td.cgray | |
17 | - = time_ago_in_words(content_commit.committed_date) | |
18 | - ago | |
19 | - %td.commit | |
20 | - - tm = @project.team_member_by_name_or_email(content_commit.author_email, content_commit.author_name) | |
21 | - - if tm | |
22 | - %strong= link_to "[#{tm.user_name}]", project_team_member_path(@project, tm) | |
23 | - = link_to truncate(content_commit.safe_message, :length => tm ? 30 : 50), project_commit_path(@project, content_commit.id), :class => "tree-commit-link" | |
6 | + %td.tree_time_ago.cgray | |
7 | + - if index == 1 | |
8 | + %span.log_loading | |
9 | + Loading commit data.. | |
10 | + = image_tag "ajax_loader_tree.gif", :width => 14 | |
11 | + %td.tree_commit | ... | ... |
app/views/refs/blame.html.haml
... | ... | @@ -11,8 +11,8 @@ |
11 | 11 | %li= link |
12 | 12 | .clear |
13 | 13 | |
14 | - .view_file.blame_file | |
15 | - .view_file_header | |
14 | + .file_holder | |
15 | + .file_title | |
16 | 16 | %i.icon-file |
17 | 17 | %span.file_name |
18 | 18 | = @tree.name |
... | ... | @@ -21,7 +21,7 @@ |
21 | 21 | = link_to "raw", blob_project_ref_path(@project, @ref, :path => params[:path]), :class => "btn very_small", :target => "_blank" |
22 | 22 | = link_to "history", project_commits_path(@project, :path => params[:path], :ref => @ref), :class => "btn very_small" |
23 | 23 | = link_to "source", tree_file_project_ref_path(@project, @ref, :path => params[:path]), :class => "btn very_small" |
24 | - .view_file_content | |
24 | + .file_content.blame | |
25 | 25 | %table |
26 | 26 | - @blame.each do |commit, lines| |
27 | 27 | - commit = Commit.new(commit) |
... | ... | @@ -29,7 +29,7 @@ |
29 | 29 | %td.author |
30 | 30 | = image_tag gravatar_icon(commit.author_email, 16) |
31 | 31 | = commit.author_name |
32 | - %td.commit | |
32 | + %td.blame_commit | |
33 | 33 | |
34 | 34 | = link_to project_commit_path(@project, :id => commit.id) do |
35 | 35 | %code= commit.id.to_s[0..10] |
... | ... | @@ -37,8 +37,7 @@ |
37 | 37 | %td.lines |
38 | 38 | = preserve do |
39 | 39 | %pre |
40 | - - lines.each do |line| | |
41 | - = line | |
40 | + = Gitlab::Encode.utf8 lines.join("\n") | |
42 | 41 | |
43 | 42 | :javascript |
44 | 43 | $(function(){ | ... | ... |
... | ... | @@ -0,0 +1,9 @@ |
1 | +- @logs.each do |content_data| | |
2 | + - file_name = content_data[:file_name] | |
3 | + - content_commit = content_data[:commit] | |
4 | + - tm = @project.team_member_by_name_or_email(content_commit.author_email, content_commit.author_name) | |
5 | + | |
6 | + :plain | |
7 | + var row = $("table.table_#{@hex_path} tr.file_#{hexdigest(file_name)}"); | |
8 | + row.find("td.tree_time_ago").html('#{escape_javascript(time_ago_in_words(content_commit.committed_date))} ago'); | |
9 | + row.find("td.tree_commit").html('#{escape_javascript(render("tree_commit", :tm => tm, :content_commit => content_commit))}'); | ... | ... |
app/views/refs/tree.js.haml
1 | 1 | :plain |
2 | + // Load Files list | |
2 | 3 | $("#tree-holder").html("#{escape_javascript(render(:partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree}))}"); |
3 | 4 | $("#tree-content-holder").show("slide", { direction: "right" }, 150); |
4 | 5 | $('.project-refs-form #path').val("#{params[:path]}"); |
6 | + | |
7 | + // Load last commit log for each file in tree | |
8 | + $('#tree-slider').waitForImages(function() { | |
9 | + ajaxGet('#{@logs_path}'); | |
10 | + }); | ... | ... |
app/views/snippets/show.html.haml
... | ... | @@ -7,16 +7,14 @@ |
7 | 7 | = link_to "Edit", edit_project_snippet_path(@project, @snippet), :class => "btn small right" |
8 | 8 | |
9 | 9 | %br |
10 | -#tree-holder | |
11 | - #tree-content-holder | |
12 | - .view_file | |
13 | - .view_file_header | |
14 | - %i.icon-file | |
15 | - %strong= @snippet.file_name | |
16 | - %span.options | |
17 | - = link_to "raw", raw_project_snippet_path(@project, @snippet), :class => "btn very_small", :target => "_blank" | |
18 | - .view_file_content | |
19 | - %div{:class => current_user.dark_scheme ? "black" : ""} | |
20 | - = raw @snippet.colorize(options: { linenos: 'True'}) | |
10 | +.file_holder | |
11 | + .file_title | |
12 | + %i.icon-file | |
13 | + %strong= @snippet.file_name | |
14 | + %span.options | |
15 | + = link_to "raw", raw_project_snippet_path(@project, @snippet), :class => "btn very_small", :target => "_blank" | |
16 | + .file_content.code | |
17 | + %div{:class => current_user.dark_scheme ? "black" : ""} | |
18 | + = raw @snippet.colorize(options: { linenos: 'True'}) | |
21 | 19 | |
22 | 20 | = render "notes/notes", :tid => @snippet.id, :tt => "snippet" | ... | ... |
config/application.rb
... | ... | @@ -23,7 +23,7 @@ module Gitlab |
23 | 23 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] |
24 | 24 | |
25 | 25 | # Activate observers that should always be running. |
26 | - config.active_record.observers = :mailer_observer, :activity_observer, :project_observer, :key_observer, :issue_observer, :user_observer | |
26 | + config.active_record.observers = :mailer_observer, :activity_observer, :project_observer, :key_observer, :issue_observer, :user_observer, :system_hook_observer | |
27 | 27 | |
28 | 28 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. |
29 | 29 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. | ... | ... |
config/gitlab.yml.example