Commit 93f0a8c9b3ca2aa4fdaccbea1547af3b0038a7dd

Authored by David Barri
2 parents 944d3823 3c7806c3

Merge remote-tracking branch 'gitlabhq/master' into git_commit_fix

Conflicts:
	doc/install/installation.md
Showing 371 changed files with 102847 additions and 1549 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 371 files displayed.

@@ -4,7 +4,7 @@ env: @@ -4,7 +4,7 @@ env:
4 before_install: 4 before_install:
5 - sudo apt-get install libicu-dev -y 5 - sudo apt-get install libicu-dev -y
6 - sudo apt-get install libqt4-dev libqtwebkit-dev -y 6 - sudo apt-get install libqt4-dev libqtwebkit-dev -y
7 - - gem install charlock_holmes -v="0.6.8" 7 + - gem install charlock_holmes -v="0.6.9"
8 branches: 8 branches:
9 only: 9 only:
10 - 'master' 10 - 'master'
@@ -28,7 +28,7 @@ v 3.0.0 @@ -28,7 +28,7 @@ v 3.0.0
28 - Reject ssh keys that break gitolite 28 - Reject ssh keys that break gitolite
29 - [API] list one project hook 29 - [API] list one project hook
30 - [API] edit project hook 30 - [API] edit project hook
31 - - [API] add project snippets list 31 + - [API] list project snippets
32 - [API] allow to authorize using private token in HTTP header 32 - [API] allow to authorize using private token in HTTP header
33 - [API] add user creation 33 - [API] add user creation
34 34
CONTRIBUTING.md
1 -## Contribute to GitLab 1 +## Contribute to GitLab
2 2
3 If you want to contribute to GitLab, follow this process: 3 If you want to contribute to GitLab, follow this process:
4 4
@@ -7,24 +7,20 @@ If you want to contribute to GitLab, follow this process: @@ -7,24 +7,20 @@ If you want to contribute to GitLab, follow this process:
7 3. Code 7 3. Code
8 4. Create a pull request 8 4. Create a pull request
9 9
10 -We will only accept pull requests if: 10 +We will only accept pull requests if:
11 11
12 * Your code has proper tests and all tests pass 12 * Your code has proper tests and all tests pass
13 -* Your code can be merged w/o problems 13 +* Your code can be merged w/o problems
14 * It won't break existing functionality 14 * It won't break existing functionality
15 * It's quality code 15 * It's quality code
16 * We like it :) 16 * We like it :)
17 17
18 -## [You may need a developer VM](https://github.com/gitlabhq/developer-vm) 18 +For examples of feedback on pull requests please look at the [closed pull requests](https://github.com/gitlabhq/gitlabhq/pulls?direction=desc&page=1&sort=created&state=closed).
19 19
20 -## Running tests  
21 -  
22 -To run the specs for GitLab, you need to run seeds for test db. 20 +## Installation
23 21
24 - cd gitlabhq  
25 - rake db:seed_fu RAILS_ENV=test 22 +Install the Gitlab development in a virtual machine with the [Gitlab Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm). Installing it in a virtual machine makes it much easier to set up all the dependencies for integration testing.
26 23
27 -Then you can run the test suite with rake:  
28 -  
29 - rake gitlab:test 24 +## Running tests
30 25
  26 +For more information on running the tests please read the [development tips](https://github.com/gitlabhq/gitlabhq/blob/master/doc/development.md)
@@ -11,9 +11,9 @@ end @@ -11,9 +11,9 @@ end
11 gem "rails", "3.2.8" 11 gem "rails", "3.2.8"
12 12
13 # Supported DBs 13 # Supported DBs
14 -gem "sqlite3", :group => :sqlite  
15 -gem "mysql2", :group => :mysql  
16 -gem "pg", :group => :postgres 14 +gem "sqlite3", group: :sqlite
  15 +gem "mysql2", group: :mysql
  16 +gem "pg", group: :postgres
17 17
18 # Auth 18 # Auth
19 gem "devise", "~> 2.1.0" 19 gem "devise", "~> 2.1.0"
@@ -23,10 +23,11 @@ gem 'omniauth-twitter' @@ -23,10 +23,11 @@ gem 'omniauth-twitter'
23 gem 'omniauth-github' 23 gem 'omniauth-github'
24 24
25 # GITLAB patched libs 25 # GITLAB patched libs
26 -gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837"  
27 -gem "omniauth-ldap", :git => "https://github.com/gitlabhq/omniauth-ldap.git", :ref => "f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e"  
28 -gem 'yaml_db', :git => "https://github.com/gitlabhq/yaml_db.git"  
29 -gem 'grack', :git => "https://github.com/gitlabhq/grack.git" 26 +gem "grit", git: "https://github.com/gitlabhq/grit.git", ref: '7f35cb98ff17d534a07e3ce6ec3d580f67402837'
  27 +gem "omniauth-ldap", git: "https://github.com/gitlabhq/omniauth-ldap.git", ref: 'f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e'
  28 +gem 'yaml_db', git: "https://github.com/gitlabhq/yaml_db.git", ref: '98e9a5dca43e3fedd3268c76a73af40d1bdf1dfd'
  29 +gem 'grack', git: "https://github.com/gitlabhq/grack.git", ref: 'ba46f3b0845c6a09d488ae6abdce6ede37e227e8'
  30 +gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '212fd40bea61f3c6a167223768e7295dc32bbc10'
30 31
31 # Gitolite client (for work with gitolite-admin repo) 32 # Gitolite client (for work with gitolite-admin repo)
32 gem "gitolite", '1.1.0' 33 gem "gitolite", '1.1.0'
@@ -35,7 +36,7 @@ gem "gitolite", '1.1.0' @@ -35,7 +36,7 @@ gem "gitolite", '1.1.0'
35 gem "pygments.rb", "0.3.1" 36 gem "pygments.rb", "0.3.1"
36 37
37 # Language detection 38 # Language detection
38 -gem "github-linguist", "~> 2.3.4" , :require => "linguist" 39 +gem "github-linguist", "~> 2.3.4" , require: "linguist"
39 40
40 # API 41 # API
41 gem "grape", "~> 0.2.1" 42 gem "grape", "~> 0.2.1"
@@ -83,9 +84,6 @@ gem 'resque_mailer' @@ -83,9 +84,6 @@ gem 'resque_mailer'
83 # HTTP requests 84 # HTTP requests
84 gem "httparty" 85 gem "httparty"
85 86
86 -# Handle encodings  
87 -gem "charlock_holmes"  
88 -  
89 # Colored output to console 87 # Colored output to console
90 gem "colored" 88 gem "colored"
91 89
@@ -114,8 +112,9 @@ group :assets do @@ -114,8 +112,9 @@ group :assets do
114 end 112 end
115 113
116 group :development do 114 group :development do
  115 + gem "annotate", git: "https://github.com/ctran/annotate_models.git"
117 gem "letter_opener" 116 gem "letter_opener"
118 - gem "annotate", :git => "https://github.com/ctran/annotate_models.git" 117 + gem 'quiet_assets', '1.0.1'
119 gem 'rack-mini-profiler' 118 gem 'rack-mini-profiler'
120 end 119 end
121 120
@@ -137,13 +136,13 @@ group :development, :test do @@ -137,13 +136,13 @@ group :development, :test do
137 gem 'guard-spinach' 136 gem 'guard-spinach'
138 137
139 # Notification 138 # Notification
140 - gem 'rb-fsevent', :require => darwin_only('rb-fsevent')  
141 - gem 'growl', :require => darwin_only('growl')  
142 - gem 'rb-inotify', :require => linux_only('rb-inotify') 139 + gem 'rb-fsevent', require: darwin_only('rb-fsevent')
  140 + gem 'growl', require: darwin_only('growl')
  141 + gem 'rb-inotify', require: linux_only('rb-inotify')
143 end 142 end
144 143
145 group :test do 144 group :test do
146 - gem "simplecov", :require => false 145 + gem "simplecov", require: false
147 gem "shoulda-matchers" 146 gem "shoulda-matchers"
148 gem 'email_spec' 147 gem 'email_spec'
149 gem 'resque_spec' 148 gem 'resque_spec'
@@ -7,6 +7,7 @@ GIT @@ -7,6 +7,7 @@ GIT
7 GIT 7 GIT
8 remote: https://github.com/gitlabhq/grack.git 8 remote: https://github.com/gitlabhq/grack.git
9 revision: ba46f3b0845c6a09d488ae6abdce6ede37e227e8 9 revision: ba46f3b0845c6a09d488ae6abdce6ede37e227e8
  10 + ref: ba46f3b0845c6a09d488ae6abdce6ede37e227e8
10 specs: 11 specs:
11 grack (1.0.0) 12 grack (1.0.0)
12 rack (~> 1.4.1) 13 rack (~> 1.4.1)
@@ -22,6 +23,14 @@ GIT @@ -22,6 +23,14 @@ GIT
22 posix-spawn (~> 0.3.6) 23 posix-spawn (~> 0.3.6)
23 24
24 GIT 25 GIT
  26 + remote: https://github.com/gitlabhq/grit_ext.git
  27 + revision: 212fd40bea61f3c6a167223768e7295dc32bbc10
  28 + ref: 212fd40bea61f3c6a167223768e7295dc32bbc10
  29 + specs:
  30 + grit_ext (0.6.0)
  31 + charlock_holmes (~> 0.6.9)
  32 +
  33 +GIT
25 remote: https://github.com/gitlabhq/omniauth-ldap.git 34 remote: https://github.com/gitlabhq/omniauth-ldap.git
26 revision: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e 35 revision: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e
27 ref: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e 36 ref: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e
@@ -35,6 +44,7 @@ GIT @@ -35,6 +44,7 @@ GIT
35 GIT 44 GIT
36 remote: https://github.com/gitlabhq/yaml_db.git 45 remote: https://github.com/gitlabhq/yaml_db.git
37 revision: 98e9a5dca43e3fedd3268c76a73af40d1bdf1dfd 46 revision: 98e9a5dca43e3fedd3268c76a73af40d1bdf1dfd
  47 + ref: 98e9a5dca43e3fedd3268c76a73af40d1bdf1dfd
38 specs: 48 specs:
39 yaml_db (0.2.2) 49 yaml_db (0.2.2)
40 50
@@ -90,7 +100,7 @@ GEM @@ -90,7 +100,7 @@ GEM
90 carrierwave (0.6.2) 100 carrierwave (0.6.2)
91 activemodel (>= 3.2.0) 101 activemodel (>= 3.2.0)
92 activesupport (>= 3.2.0) 102 activesupport (>= 3.2.0)
93 - charlock_holmes (0.6.8) 103 + charlock_holmes (0.6.9)
94 childprocess (0.3.2) 104 childprocess (0.3.2)
95 ffi (~> 1.0.6) 105 ffi (~> 1.0.6)
96 chosen-rails (0.9.8.3) 106 chosen-rails (0.9.8.3)
@@ -260,6 +270,8 @@ GEM @@ -260,6 +270,8 @@ GEM
260 posix-spawn (~> 0.3.6) 270 posix-spawn (~> 0.3.6)
261 yajl-ruby (~> 1.1.0) 271 yajl-ruby (~> 1.1.0)
262 pyu-ruby-sasl (0.0.3.3) 272 pyu-ruby-sasl (0.0.3.3)
  273 + quiet_assets (1.0.1)
  274 + railties (~> 3.1)
263 rack (1.4.1) 275 rack (1.4.1)
264 rack-cache (1.2) 276 rack-cache (1.2)
265 rack (>= 0.4) 277 rack (>= 0.4)
@@ -411,7 +423,6 @@ DEPENDENCIES @@ -411,7 +423,6 @@ DEPENDENCIES
411 capybara 423 capybara
412 capybara-webkit 424 capybara-webkit
413 carrierwave 425 carrierwave
414 - charlock_holmes  
415 chosen-rails 426 chosen-rails
416 coffee-rails (= 3.2.2) 427 coffee-rails (= 3.2.2)
417 colored 428 colored
@@ -432,6 +443,7 @@ DEPENDENCIES @@ -432,6 +443,7 @@ DEPENDENCIES
432 grack! 443 grack!
433 grape (~> 0.2.1) 444 grape (~> 0.2.1)
434 grit! 445 grit!
  446 + grit_ext!
435 growl 447 growl
436 guard-rspec 448 guard-rspec
437 guard-spinach 449 guard-spinach
@@ -454,6 +466,7 @@ DEPENDENCIES @@ -454,6 +466,7 @@ DEPENDENCIES
454 pg 466 pg
455 pry 467 pry
456 pygments.rb (= 0.3.1) 468 pygments.rb (= 0.3.1)
  469 + quiet_assets (= 1.0.1)
457 rack-mini-profiler 470 rack-mini-profiler
458 rails (= 3.2.8) 471 rails (= 3.2.8)
459 rails-dev-tweaks 472 rails-dev-tweaks
Procfile.production
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -web: bundle exec rails s -p $PORT -e production  
2 -worker: bundle exec rake environment resque:work RAILS_ENV=production QUEUE=*  
ROADMAP.md 0 → 100644
@@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
  1 +## GitLab Roadmap
  2 +
  3 +### Common
  4 +
  5 +* Help page for service tasks like repos import, backup etc
  6 +* Hide last push widget after following link
  7 +* Add comment events
  8 +* Dashboard/Project activity events filter
  9 +
  10 +### Issues
  11 +
  12 +* labels autocomplete via jquery autocomplete
  13 +* Import/Export issues
  14 +* Form: Assign to me link right to the selectbox
  15 +
  16 +### Merge Request
  17 +
  18 +* CI build status
  19 +* Save code fragments with MR comments
1 -3.0.3 1 +3.1.0pre
app/assets/images/event_filter_comments.png 0 → 100644

750 Bytes

app/assets/images/event_filter_merged.png 0 → 100644

463 Bytes

app/assets/images/event_filter_push.png 0 → 100644

632 Bytes

app/assets/images/event_filter_team.png 0 → 100644

1.31 KB

app/assets/javascripts/application.js
@@ -17,6 +17,8 @@ @@ -17,6 +17,8 @@
17 //= require modernizr 17 //= require modernizr
18 //= require chosen-jquery 18 //= require chosen-jquery
19 //= require raphael 19 //= require raphael
  20 +//= require g.raphael-min
  21 +//= require g.bar-min
20 //= require branch-graph 22 //= require branch-graph
21 //= require ace-src-noconflict/ace 23 //= require ace-src-noconflict/ace
22 //= require_tree . 24 //= require_tree .
app/assets/javascripts/gfm_auto_complete.js.coffee
  1 +# Creates the variables for setting up GFM auto-completion
1 2
2 -###  
3 - Creates the variables for setting up GFM auto-completion  
4 -###  
5 # Emoji 3 # Emoji
6 -window.autocompleteEmojiData = [];  
7 -window.autocompleteEmojiTemplate = "<li data-value='${insert}'>${name} <img alt='${name}' height='20' src='${image}' width='20' /></li>"; 4 +data = []
  5 +template = "<li data-value='${insert}'>${name} <img alt='${name}' height='20' src='${image}' width='20' /></li>"
  6 +window.autocompleteEmoji = {data, template}
8 7
9 # Team Members 8 # Team Members
10 -window.autocompleteMembersUrl = "";  
11 -window.autocompleteMembersParams =  
12 - private_token: ""  
13 - page: 1  
14 -window.autocompleteMembersData = []; 9 +url = '';
  10 +params = {private_token: '', page: 1}
  11 +window.autocompleteMembers = {data, url, params}
15 12
  13 +# Add GFM auto-completion to all input fields, that accept GFM input.
  14 +window.setupGfmAutoComplete = ->
  15 + $input = $('.js-gfm-input')
16 16
  17 + # Emoji
  18 + $input.atWho ':',
  19 + data: autocompleteEmoji.data,
  20 + tpl: autocompleteEmoji.template
17 21
18 -###  
19 - Add GFM auto-completion to all input fields, that accept GFM input.  
20 -###  
21 -window.setupGfmAutoComplete = ->  
22 - ###  
23 - Emoji  
24 - ###  
25 - $('.gfm-input').atWho ':',  
26 - data: autocompleteEmojiData,  
27 - tpl: autocompleteEmojiTemplate  
28 -  
29 - ###  
30 - Team Members  
31 - ###  
32 - $('.gfm-input').atWho '@', (query, callback) -> 22 + # Team Members
  23 + $input.atWho '@', (query, callback) ->
33 (getMoreMembers = -> 24 (getMoreMembers = ->
34 - $.getJSON(autocompleteMembersUrl, autocompleteMembersParams)  
35 - .success (members) ->  
36 - # pick the data we need  
37 - newMembersData = $.map members, (m) -> m.name  
38 -  
39 - # add the new page of data to the rest  
40 - $.merge autocompleteMembersData, newMembersData  
41 -  
42 - # show the pop-up with a copy of the current data  
43 - callback autocompleteMembersData[..]  
44 -  
45 - # are we past the last page?  
46 - if newMembersData.length == 0  
47 - # set static data and stop callbacks  
48 - $('.gfm-input').atWho '@',  
49 - data: autocompleteMembersData  
50 - callback: null  
51 - else  
52 - # get next page  
53 - getMoreMembers() 25 + $.getJSON(autocompleteMembers.url, autocompleteMembers.params).success (members) ->
  26 + # pick the data we need
  27 + newMembersData = $.map members, (m) -> m.name
  28 +
  29 + # add the new page of data to the rest
  30 + $.merge autocompleteMembers.data, newMembersData
  31 +
  32 + # show the pop-up with a copy of the current data
  33 + callback autocompleteMembers.data[..]
  34 +
  35 + # are we past the last page?
  36 + if newMembersData.length is 0
  37 + # set static data and stop callbacks
  38 + $input.atWho '@',
  39 + data: autocompleteMembers.data
  40 + callback: null
  41 + else
  42 + # get next page
  43 + getMoreMembers()
54 44
55 # so the next request gets the next page 45 # so the next request gets the next page
56 - autocompleteMembersParams.page += 1;  
57 - ).call();  
58 \ No newline at end of file 46 \ No newline at end of file
  47 + autocompleteMembers.params.page += 1
  48 + ).call()
app/assets/javascripts/graph.js.coffee
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -initGraphNav = ->  
2 - $('.graph svg').css 'position', 'relative'  
3 -  
4 - $('body').bind 'keyup', (e) ->  
5 - if e.keyCode is 37 # left  
6 - $('.graph svg').animate left: '+=400'  
7 - else if e.keyCode is 39 # right  
8 - $('.graph svg').animate left: '-=400'  
9 -  
10 -window.initGraphNav = initGraphNav  
app/assets/javascripts/issues.js
1 -function switchToNewIssue(form){ 1 +function switchToNewIssue(){
2 $(".issues_content").hide("fade", { direction: "left" }, 150, function(){ 2 $(".issues_content").hide("fade", { direction: "left" }, 150, function(){
3 - $(".issues_content").after(form);  
4 $('select#issue_assignee_id').chosen(); 3 $('select#issue_assignee_id').chosen();
5 $('select#issue_milestone_id').chosen(); 4 $('select#issue_milestone_id').chosen();
6 $("#new_issue_dialog").show("fade", { direction: "right" }, 150); 5 $("#new_issue_dialog").show("fade", { direction: "right" }, 150);
@@ -10,9 +9,8 @@ function switchToNewIssue(form){ @@ -10,9 +9,8 @@ function switchToNewIssue(form){
10 }); 9 });
11 } 10 }
12 11
13 -function switchToEditIssue(form){ 12 +function switchToEditIssue(){
14 $(".issues_content").hide("fade", { direction: "left" }, 150, function(){ 13 $(".issues_content").hide("fade", { direction: "left" }, 150, function(){
15 - $(".issues_content").after(form);  
16 $('select#issue_assignee_id').chosen(); 14 $('select#issue_assignee_id').chosen();
17 $('select#issue_milestone_id').chosen(); 15 $('select#issue_milestone_id').chosen();
18 $("#edit_issue_dialog").show("fade", { direction: "right" }, 150); 16 $("#edit_issue_dialog").show("fade", { direction: "right" }, 150);
@@ -33,8 +31,8 @@ function switchFromEditIssue(){ @@ -33,8 +31,8 @@ function switchFromEditIssue(){
33 function backToIssues(){ 31 function backToIssues(){
34 $("#edit_issue_dialog, #new_issue_dialog").hide("fade", { direction: "right" }, 150, function(){ 32 $("#edit_issue_dialog, #new_issue_dialog").hide("fade", { direction: "right" }, 150, function(){
35 $(".issues_content").show("fade", { direction: "left" }, 150, function() { 33 $(".issues_content").show("fade", { direction: "left" }, 150, function() {
36 - $("#edit_issue_dialog").remove();  
37 - $("#new_issue_dialog").remove(); 34 + $("#edit_issue_dialog").html("");
  35 + $("#new_issue_dialog").html("");
38 $('.add_new').show(); 36 $('.add_new').show();
39 }); 37 });
40 }); 38 });
app/assets/javascripts/loader.js.coffee
@@ -1,5 +0,0 @@ @@ -1,5 +0,0 @@
1 -Loader =  
2 - html: (width) ->  
3 - $('<img>').attr src: '/assets/ajax-loader.gif', width: width  
4 -  
5 -window.Loader = Loader  
app/assets/javascripts/main.js.coffee
@@ -7,29 +7,32 @@ window.slugify = (text) -&gt; @@ -7,29 +7,32 @@ window.slugify = (text) -&gt;
7 window.ajaxGet = (url) -> 7 window.ajaxGet = (url) ->
8 $.ajax({type: "GET", url: url, dataType: "script"}) 8 $.ajax({type: "GET", url: url, dataType: "script"})
9 9
10 - # Disable button if text field is empty 10 +# Disable button if text field is empty
11 window.disableButtonIfEmptyField = (field_selector, button_selector) -> 11 window.disableButtonIfEmptyField = (field_selector, button_selector) ->
12 field = $(field_selector) 12 field = $(field_selector)
13 closest_submit = field.closest("form").find(button_selector) 13 closest_submit = field.closest("form").find(button_selector)
14 14
15 closest_submit.disable() if field.val() is "" 15 closest_submit.disable() if field.val() is ""
16 16
17 - field.on "keyup", ->  
18 - if $(this).val() is "" 17 + field.on "input", ->
  18 + if $(@).val() is ""
19 closest_submit.disable() 19 closest_submit.disable()
20 else 20 else
21 closest_submit.enable() 21 closest_submit.enable()
22 22
23 $ -> 23 $ ->
24 # Click a .one_click_select field, select the contents 24 # Click a .one_click_select field, select the contents
25 - $(".one_click_select").live 'click', -> $(this).select() 25 + $(".one_click_select").on 'click', -> $(@).select()
26 26
27 # Initialize chosen selects 27 # Initialize chosen selects
28 $('select.chosen').chosen() 28 $('select.chosen').chosen()
29 29
  30 + # Initialize tooltips
  31 + $('.has_tooltip').tooltip()
  32 +
30 # Disable form buttons while a form is submitting 33 # Disable form buttons while a form is submitting
31 $('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) -> 34 $('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) ->
32 - buttons = $('[type="submit"]', this) 35 + buttons = $('[type="submit"]', @)
33 36
34 switch e.type 37 switch e.type
35 when 'ajax:beforeSend', 'submit' 38 when 'ajax:beforeSend', 'submit'
@@ -38,7 +41,7 @@ $ -&gt; @@ -38,7 +41,7 @@ $ -&gt;
38 buttons.enable() 41 buttons.enable()
39 42
40 # Show/Hide the profile menu when hovering the account box 43 # Show/Hide the profile menu when hovering the account box
41 - $('.account-box').hover -> $(this).toggleClass('hover') 44 + $('.account-box').hover -> $(@).toggleClass('hover')
42 45
43 # Focus search field by pressing 's' key 46 # Focus search field by pressing 's' key
44 $(document).keypress (e) -> 47 $(document).keypress (e) ->
@@ -52,22 +55,22 @@ $ -&gt; @@ -52,22 +55,22 @@ $ -&gt;
52 55
53 # Commit show suppressed diff 56 # Commit show suppressed diff
54 $(".supp_diff_link").bind "click", -> 57 $(".supp_diff_link").bind "click", ->
55 - $(this).next('table').show()  
56 - $(this).remove() 58 + $(@).next('table').show()
  59 + $(@).remove()
57 60
58 # Note markdown preview 61 # Note markdown preview
59 $(document).on 'click', '#preview-link', (e) -> 62 $(document).on 'click', '#preview-link', (e) ->
60 - $('#preview-note').text('Loading...') 63 + $('#preview-note').text 'Loading...'
61 64
62 - previewLinkText = if $(this).text() == 'Preview' then 'Edit' else 'Preview'  
63 - $(this).text(previewLinkText) 65 + previewLinkText = if $(@).text() is 'Preview' then 'Edit' else 'Preview'
  66 + $(@).text previewLinkText
64 67
65 note = $('#note_note').val() 68 note = $('#note_note').val()
66 69
67 - if note.trim().length == 0  
68 - $('#preview-note').text("Nothing to preview.") 70 + if note.trim().length is 0
  71 + $('#preview-note').text 'Nothing to preview.'
69 else 72 else
70 - $.post $(this).attr('href'), {note: note}, (data) -> 73 + $.post $(@).attr('href'), {note: note}, (data) ->
71 $('#preview-note').html(data) 74 $('#preview-note').html(data)
72 75
73 $('#preview-note, #note_note').toggle() 76 $('#preview-note, #note_note').toggle()
@@ -79,14 +82,14 @@ $ -&gt; @@ -79,14 +82,14 @@ $ -&gt;
79 $.fn.extend chosen: (options) -> 82 $.fn.extend chosen: (options) ->
80 default_options = search_contains: "true" 83 default_options = search_contains: "true"
81 $.extend default_options, options 84 $.extend default_options, options
82 - _chosen.apply this, [default_options] 85 + _chosen.apply @, [default_options]
83 86
84 # Disable an element and add the 'disabled' Bootstrap class 87 # Disable an element and add the 'disabled' Bootstrap class
85 $.fn.extend disable: -> 88 $.fn.extend disable: ->
86 - $(this).attr('disabled', 'disabled').addClass('disabled') 89 + $(@).attr('disabled', 'disabled').addClass('disabled')
87 90
88 # Enable an element and remove the 'disabled' Bootstrap class 91 # Enable an element and remove the 'disabled' Bootstrap class
89 $.fn.extend enable: -> 92 $.fn.extend enable: ->
90 - $(this).removeAttr('disabled').removeClass('disabled') 93 + $(@).removeAttr('disabled').removeClass('disabled')
91 94
92 )(jQuery) 95 )(jQuery)
app/assets/javascripts/merge_requests.js
@@ -115,4 +115,15 @@ var MergeRequest = { @@ -115,4 +115,15 @@ var MergeRequest = {
115 $(".merge_in_progress").hide(); 115 $(".merge_in_progress").hide();
116 $(".automerge_widget.already_cannot_be_merged").show(); 116 $(".automerge_widget.already_cannot_be_merged").show();
117 } 117 }
  118 +};
  119 +
  120 +/*
  121 + * Filter merge requests
  122 + */
  123 +function merge_requestsPage() {
  124 + $("#assignee_id").chosen();
  125 + $("#milestone_id").chosen();
  126 + $("#milestone_id, #assignee_id").on("change", function(){
  127 + $(this).closest("form").submit();
  128 + });
118 } 129 }
app/assets/javascripts/milestones.js.coffee
@@ -5,3 +5,10 @@ $ -&gt; @@ -5,3 +5,10 @@ $ -&gt;
5 $('.milestone-issue-filter li').toggleClass('active') 5 $('.milestone-issue-filter li').toggleClass('active')
6 $('.milestone-issue-filter tr[data-closed]').toggleClass('hide') 6 $('.milestone-issue-filter tr[data-closed]').toggleClass('hide')
7 false 7 false
  8 +
  9 + $('.milestone-merge-requests-filter tr[data-closed]').addClass('hide')
  10 +
  11 + $('.milestone-merge-requests-filter ul.nav li a').click ->
  12 + $('.milestone-merge-requests-filter li').toggleClass('active')
  13 + $('.milestone-merge-requests-filter tr[data-closed]').toggleClass('hide')
  14 + false
app/assets/javascripts/projects.js.coffee
@@ -22,3 +22,10 @@ $ -&gt; @@ -22,3 +22,10 @@ $ -&gt;
22 # Ref switcher 22 # Ref switcher
23 $('.project-refs-select').on 'change', -> 23 $('.project-refs-select').on 'change', ->
24 $(@).parents('form').submit() 24 $(@).parents('form').submit()
  25 +
  26 +class @GraphNav
  27 + @init: ->
  28 + $('.graph svg').css 'position', 'relative'
  29 + $('body').bind 'keyup', (e) ->
  30 + $('.graph svg').animate(left: '+=400') if e.keyCode is 37 # left
  31 + $('.graph svg').animate(left: '-=400') if e.keyCode is 39 # right
app/assets/javascripts/snippets.js.coffee
@@ -1,6 +0,0 @@ @@ -1,6 +0,0 @@
1 -$ ->  
2 - $('#snippets-table .snippet').live 'click', (e) ->  
3 - if e.target.nodeName isnt 'A' and e.target.nodeName isnt 'INPUT'  
4 - location.href = $(@).attr 'url'  
5 - e.stopPropagation()  
6 - false  
app/assets/javascripts/tree.js.coffee
@@ -17,23 +17,21 @@ $ -&gt; @@ -17,23 +17,21 @@ $ -&gt;
17 "ajax:beforeSend": -> $('.tree_progress').addClass("loading") 17 "ajax:beforeSend": -> $('.tree_progress').addClass("loading")
18 "ajax:complete": -> $('.tree_progress').removeClass("loading") 18 "ajax:complete": -> $('.tree_progress').removeClass("loading")
19 19
20 -# Maintain forward/back history while browsing the file tree  
21 -  
22 -((window) ->  
23 - History = window.History  
24 - $ = window.jQuery  
25 - document = window.document  
26 -  
27 - # Check to see if History.js is enabled for our Browser  
28 - unless History.enabled  
29 - return false  
30 -  
31 - $ ->  
32 - $('#tree-slider .tree-item-file-name a, .breadcrumb li > a').live 'click', (e) ->  
33 - History.pushState(null, null, $(@).attr('href'))  
34 - return false  
35 -  
36 - History.Adapter.bind window, 'statechange', ->  
37 - state = History.getState()  
38 - window.ajaxGet(state.url)  
39 -)(window) 20 + # Maintain forward/back history while browsing the file tree
  21 + ((window) ->
  22 + History = window.History
  23 + $ = window.jQuery
  24 + document = window.document
  25 +
  26 + # Check to see if History.js is enabled for our Browser
  27 + unless History.enabled
  28 + return false
  29 +
  30 + $('#tree-slider .tree-item-file-name a, .breadcrumb li > a').live 'click', (e) ->
  31 + History.pushState(null, null, $(@).attr('href'))
  32 + return false
  33 +
  34 + History.Adapter.bind window, 'statechange', ->
  35 + state = History.getState()
  36 + window.ajaxGet(state.url)
  37 + )(window)
app/assets/stylesheets/common.scss
@@ -670,3 +670,16 @@ pre { @@ -670,3 +670,16 @@ pre {
670 padding:0; 670 padding:0;
671 } 671 }
672 } 672 }
  673 +
  674 +.milestone .progress {
  675 + margin-bottom: 0;
  676 + margin-top:4px;
  677 +}
  678 +
  679 +.float-link {
  680 + float:left;
  681 + margin-right:15px;
  682 + .s16 {
  683 + margin-right:5px;
  684 + }
  685 +}
app/assets/stylesheets/gitlab_bootstrap/common.scss
@@ -26,8 +26,10 @@ @@ -26,8 +26,10 @@
26 .underlined { border-bottom: 1px solid #CCC; } 26 .underlined { border-bottom: 1px solid #CCC; }
27 .no-borders { border:none; } 27 .no-borders { border:none; }
28 .vlink { color: $link_color !important; } 28 .vlink { color: $link_color !important; }
  29 +.underlined_link { text-decoration: underline; }
29 .borders { border: 1px solid #ccc; @include shade; } 30 .borders { border: 1px solid #ccc; @include shade; }
30 .hint { font-style: italic; color: #999; } 31 .hint { font-style: italic; color: #999; }
  32 +.light { color: #888 }
31 33
32 /** PILLS & TABS**/ 34 /** PILLS & TABS**/
33 .nav-pills a:hover { background-color:#888; } 35 .nav-pills a:hover { background-color:#888; }
@@ -66,10 +68,10 @@ @@ -66,10 +68,10 @@
66 .alert-message.error { @extend .alert-error; } 68 .alert-message.error { @extend .alert-error; }
67 69
68 /** AVATARS **/ 70 /** AVATARS **/
69 -img.avatar { float:left; margin-right:15px; width:40px; border:1px solid #ddd; padding:1px; }  
70 -img.avatar.s16 { width:16px; height:16px; }  
71 -img.avatar.s24 { width:24px; height:24px; }  
72 -img.avatar.s32 { width:32px; height:32px; } 71 +img.avatar { float:left; margin-right:12px; width:40px; border:1px solid #ddd; padding:1px; }
  72 +img.avatar.s16 { width:16px; height:16px; margin-right:6px; }
  73 +img.avatar.s24 { width:24px; height:24px; margin-right:8px; }
  74 +img.avatar.s32 { width:32px; height:32px; margin-right:10px; }
73 img.lil_av { padding-left: 4px; padding-right:3px; } 75 img.lil_av { padding-left: 4px; padding-right:3px; }
74 76
75 /** HELPERS **/ 77 /** HELPERS **/
app/assets/stylesheets/gitlab_bootstrap/files.scss
@@ -157,10 +157,15 @@ @@ -157,10 +157,15 @@
157 font-size:12px !important; 157 font-size:12px !important;
158 } 158 }
159 159
160 - table.highlighttable .linenodiv pre {  
161 - text-align: right;  
162 - padding-right: 4px;  
163 - color:#666; 160 + table.highlighttable .linenodiv {
  161 + a {
  162 + color: #666;
  163 + }
  164 + pre {
  165 + text-align: right;
  166 + padding-right: 4px;
  167 + color:#666;
  168 + }
164 } 169 }
165 } 170 }
166 } 171 }
app/assets/stylesheets/gitlab_bootstrap/lists.scss
@@ -21,7 +21,7 @@ ul { @@ -21,7 +21,7 @@ ul {
21 .author { color: #999; } 21 .author { color: #999; }
22 22
23 p { 23 p {
24 - padding-top:5px; 24 + padding-top: 1px;
25 margin:0; 25 margin:0;
26 color:#222; 26 color:#222;
27 img { 27 img {
@@ -31,3 +31,11 @@ ul { @@ -31,3 +31,11 @@ ul {
31 } 31 }
32 } 32 }
33 } 33 }
  34 +
  35 +ol, ul {
  36 + &.styled {
  37 + li {
  38 + padding:2px;
  39 + }
  40 + }
  41 +}
app/assets/stylesheets/gitlab_bootstrap/tables.scss
@@ -34,6 +34,11 @@ table { @@ -34,6 +34,11 @@ table {
34 border-color:#f1f1f1; 34 border-color:#f1f1f1;
35 line-height:28px; 35 line-height:28px;
36 36
  37 + .s16 {
  38 + margin-top: 5px;
  39 + margin-right: 5px;
  40 + }
  41 +
37 &:first-child { 42 &:first-child {
38 border-left:1px solid #bbb; 43 border-left:1px solid #bbb;
39 } 44 }
app/assets/stylesheets/main.scss
@@ -3,10 +3,11 @@ @@ -3,10 +3,11 @@
3 @import 'font-awesome'; 3 @import 'font-awesome';
4 4
5 /** GitLab colors **/ 5 /** GitLab colors **/
6 -$link_color:#3A89A3;  
7 -$blue_link: #2fa0bb;  
8 -$style_color: #474d57; 6 +$link_color: #3A89A3;
  7 +$blue_link: #2FA0BB;
  8 +$style_color: #474D57;
9 $hover: #D9EDF7; 9 $hover: #D9EDF7;
  10 +$hover_border: #ADF;
10 11
11 /** GitLab Fonts **/ 12 /** GitLab Fonts **/
12 @font-face { font-family: Korolev; src: font-url('korolev-medium-compressed.otf'); } 13 @font-face { font-family: Korolev; src: font-url('korolev-medium-compressed.otf'); }
@@ -19,9 +20,9 @@ $hover: #D9EDF7; @@ -19,9 +20,9 @@ $hover: #D9EDF7;
19 } 20 }
20 21
21 @mixin solid_shade { 22 @mixin solid_shade {
22 - -moz-box-shadow: 0 0 0 3px #eee;  
23 - -webkit-box-shadow: 0 0 0 3px #eee;  
24 - box-shadow: 0 0 0 3px #eee; 23 + -moz-box-shadow: 0 0 0 3px #f1f1f1;
  24 + -webkit-box-shadow: 0 0 0 3px #f1f1f1;
  25 + box-shadow: 0 0 0 3px #f1f1f1;
25 } 26 }
26 27
27 @mixin border-radius($radius) { 28 @mixin border-radius($radius) {
@@ -64,6 +65,14 @@ $hover: #D9EDF7; @@ -64,6 +65,14 @@ $hover: #D9EDF7;
64 background-image: -o-linear-gradient($from, $to); 65 background-image: -o-linear-gradient($from, $to);
65 } 66 }
66 67
  68 +@mixin bg-light-gray-gradient {
  69 + background:#f1f1f1;
  70 + background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #f5f5f5), to(#e1e1e1));
  71 + background-image: -webkit-linear-gradient(#f5f5f5 6.6%, #e1e1e1);
  72 + background-image: -moz-linear-gradient(#f5f5f5 6.6%, #e1e1e1);
  73 + background-image: -o-linear-gradient(#f5f5f5 6.6%, #e1e1e1);
  74 +}
  75 +
67 @mixin bg-gray-gradient { 76 @mixin bg-gray-gradient {
68 background:#eee; 77 background:#eee;
69 background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); 78 background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
app/assets/stylesheets/ref_select.scss
@@ -19,31 +19,66 @@ @@ -19,31 +19,66 @@
19 margin-right: 10px; 19 margin-right: 10px;
20 20
21 .chzn-drop { 21 .chzn-drop {
22 - margin:7px 0;  
23 min-width: 400px; 22 min-width: 400px;
24 - border: 2px solid $blue_link;  
25 - @include border-radius(4px); 23 + .chzn-results {
  24 + max-height:300px;
  25 + }
  26 + .chzn-search input {
  27 + min-width:365px;
  28 + }
  29 + }
  30 +}
  31 +
  32 +/** Fix for Search Dropdown Border **/
  33 +.chzn-container {
  34 + .chzn-search {
  35 + input:focus {
  36 + -webkit-box-shadow: none;
  37 + -moz-box-shadow: none;
  38 + box-shadow: none;
  39 + }
  40 + }
  41 +
  42 + .chzn-drop {
  43 + margin:7px 0;
  44 + min-width: 200px;
  45 + border: 1px solid #bbb;
  46 + border-radius:0;
26 47
27 .chzn-results { 48 .chzn-results {
  49 + margin-top: 5px;
28 max-height:300px; 50 max-height:300px;
29 51
30 .group-result { 52 .group-result {
31 - color: $blue_link; 53 + color: $style_color;
  54 + border-bottom: 1px solid #EEE;
  55 + padding: 8px;
32 } 56 }
33 .active-result { 57 .active-result {
  58 + border-radius: 0;
  59 +
34 &.highlighted { 60 &.highlighted {
35 - background: $blue_link; 61 + background: $hover;
  62 + color: $style_color;
  63 + }
  64 + &.result-selected {
  65 + background: #EEE;
  66 + border-left: 4px solid #CCC;
36 } 67 }
37 } 68 }
38 } 69 }
39 70
40 - .chzn-search input {  
41 - min-width:365px; 71 + .chzn-search {
  72 + @include bg-gray-gradient;
  73 + input {
  74 + min-width:165px;
  75 + border-color: #CCC;
  76 + }
42 } 77 }
43 } 78 }
44 79
45 .chzn-single { 80 .chzn-single {
46 - @include bg-gray-gradient; 81 + @include bg-light-gray-gradient;
47 82
48 div { 83 div {
49 background:transparent; 84 background:transparent;
@@ -55,14 +90,3 @@ @@ -55,14 +90,3 @@
55 } 90 }
56 } 91 }
57 } 92 }
58 -  
59 -/** Fix for Search Dropdown Border **/  
60 -.chzn-container {  
61 - .chzn-search {  
62 - input:focus {  
63 - -webkit-box-shadow: none;  
64 - -moz-box-shadow: none;  
65 - box-shadow: none;  
66 - }  
67 - }  
68 -}  
app/assets/stylesheets/sections/commits.scss
@@ -47,12 +47,15 @@ @@ -47,12 +47,15 @@
47 padding-left: 32px; 47 padding-left: 32px;
48 } 48 }
49 49
50 - .author,  
51 - .committer { 50 + .author a,
  51 + .committer a {
52 font-size:14px; 52 font-size:14px;
53 line-height:22px; 53 line-height:22px;
54 text-shadow:0 1px 1px #fff; 54 text-shadow:0 1px 1px #fff;
55 color:#777; 55 color:#777;
  56 + &:hover {
  57 + color: #999;
  58 + }
56 } 59 }
57 60
58 .avatar { 61 .avatar {
@@ -227,6 +230,9 @@ @@ -227,6 +230,9 @@
227 230
228 .commit-author-name { 231 .commit-author-name {
229 color: #777; 232 color: #777;
  233 + &:hover {
  234 + color: #999;
  235 + }
230 } 236 }
231 } 237 }
232 238
app/assets/stylesheets/sections/events.scss
@@ -43,6 +43,7 @@ @@ -43,6 +43,7 @@
43 .event-body { 43 .event-body {
44 p { 44 p {
45 color:#555; 45 color:#555;
  46 + padding-top: 5px;
46 } 47 }
47 .event-info { 48 .event-info {
48 color:#666; 49 color:#666;
@@ -115,3 +116,29 @@ @@ -115,3 +116,29 @@
115 margin: -3px; 116 margin: -3px;
116 } 117 }
117 } 118 }
  119 +
  120 +/**
  121 + * Event filter
  122 + *
  123 + */
  124 +.event_filter {
  125 + position: absolute;
  126 + width: 40px;
  127 + margin-left: -50px;
  128 +
  129 + .filter_icon {
  130 + float: left;
  131 + border-left: 3px solid #4bc;
  132 + padding: 7px;
  133 + background: #f9f9f9;
  134 + margin-bottom: 10px;
  135 + img {
  136 + width:20px;
  137 + }
  138 +
  139 + &.inactive {
  140 + border-left: 3px solid #EEE;
  141 + opacity: 0.5;
  142 + }
  143 + }
  144 +}
app/assets/stylesheets/sections/issues.scss
@@ -44,7 +44,7 @@ @@ -44,7 +44,7 @@
44 44
45 img.avatar { 45 img.avatar {
46 width:32px; 46 width:32px;
47 - margin-top:4px; 47 + margin-top:1px;
48 } 48 }
49 } 49 }
50 } 50 }
app/assets/stylesheets/sections/merge_requests.scss
@@ -71,7 +71,7 @@ li.merge_request { @@ -71,7 +71,7 @@ li.merge_request {
71 padding:7px 10px; 71 padding:7px 10px;
72 img.avatar { 72 img.avatar {
73 width: 32px; 73 width: 32px;
74 - margin-top: 4px; 74 + margin-top: 1px;
75 } 75 }
76 p { 76 p {
77 padding: 0px; 77 padding: 0px;
@@ -121,3 +121,20 @@ li.merge_request { @@ -121,3 +121,20 @@ li.merge_request {
121 .mr_direction_tip { 121 .mr_direction_tip {
122 margin-top:40px 122 margin-top:40px
123 } 123 }
  124 +
  125 +.merge_requests_form_box {
  126 + @extend .main_box;
  127 + .merge_requests_middle_box {
  128 + @extend .middle_box_content;
  129 + height:30px;
  130 + .merge_requests_assignee {
  131 + @extend .span6;
  132 + float:left;
  133 + }
  134 + .merge_requests_milestone {
  135 + @extend .span4;
  136 + float:left;
  137 + }
  138 + }
  139 +}
  140 +
app/assets/stylesheets/sections/tree.scss
@@ -57,10 +57,7 @@ @@ -57,10 +57,7 @@
57 padding-right: 8px; 57 padding-right: 8px;
58 58
59 img.avatar { 59 img.avatar {
60 - border: 0 none;  
61 - float: none;  
62 - margin-right: 0;  
63 - padding: 0; 60 + margin-top: 0;
64 width: 16px; 61 width: 16px;
65 } 62 }
66 } 63 }
@@ -75,6 +72,15 @@ @@ -75,6 +72,15 @@
75 } 72 }
76 } 73 }
77 } 74 }
  75 +
  76 + .blame {
  77 + img.avatar {
  78 + border: 0 none;
  79 + float: none;
  80 + margin: 0;
  81 + padding: 0;
  82 + }
  83 + }
78 } 84 }
79 85
80 .tree-btn-group { 86 .tree-btn-group {
app/assets/stylesheets/themes/ui_mars.scss
@@ -37,9 +37,6 @@ @@ -37,9 +37,6 @@
37 background-image: -o-linear-gradient(#595D63 6.6%, #202227); 37 background-image: -o-linear-gradient(#595D63 6.6%, #202227);
38 background-position:0 0; 38 background-position:0 0;
39 color:#fff; 39 color:#fff;
40 - i {  
41 - @extend .icon-white;  
42 - }  
43 } 40 }
44 41
45 border: 1px solid #31363E; 42 border: 1px solid #31363E;
app/assets/stylesheets/themes/ui_modern.scss
@@ -70,9 +70,6 @@ @@ -70,9 +70,6 @@
70 color:#ccc; 70 color:#ccc;
71 &:hover { 71 &:hover {
72 color:#fff; 72 color:#fff;
73 - i {  
74 - @extend .icon-white;  
75 - }  
76 } 73 }
77 border: none; 74 border: none;
78 box-shadow:none; 75 box-shadow:none;
app/contexts/commit_load_context.rb
@@ -21,7 +21,7 @@ class CommitLoadContext &lt; BaseContext @@ -21,7 +21,7 @@ class CommitLoadContext &lt; BaseContext
21 result[:notes_count] = line_notes.count + project.commit_notes(commit).count 21 result[:notes_count] = line_notes.count + project.commit_notes(commit).count
22 22
23 begin 23 begin
24 - result[:suppress_diff] = true if commit.diffs.size > 200 && !params[:force_show_diff] 24 + result[:suppress_diff] = true if commit.diffs.size > Commit::DIFF_SAFE_SIZE && !params[:force_show_diff]
25 rescue Grit::Git::GitTimeout 25 rescue Grit::Git::GitTimeout
26 result[:suppress_diff] = true 26 result[:suppress_diff] = true
27 result[:status] = :huge_commit 27 result[:status] = :huge_commit
app/contexts/merge_requests_load_context.rb
  1 +# Build collection of Merge Requests
  2 +# based on filtering passed via params for @project
1 class MergeRequestsLoadContext < BaseContext 3 class MergeRequestsLoadContext < BaseContext
2 def execute 4 def execute
3 type = params[:f] 5 type = params[:f]
@@ -9,8 +11,21 @@ class MergeRequestsLoadContext &lt; BaseContext @@ -9,8 +11,21 @@ class MergeRequestsLoadContext &lt; BaseContext
9 when 'closed' then merge_requests.closed 11 when 'closed' then merge_requests.closed
10 when 'assigned-to-me' then merge_requests.opened.assigned(current_user) 12 when 'assigned-to-me' then merge_requests.opened.assigned(current_user)
11 else merge_requests.opened 13 else merge_requests.opened
12 - end.page(params[:page]).per(20) 14 + end
13 15
14 - merge_requests.includes(:author, :project).order("closed, created_at desc") 16 + merge_requests = merge_requests.page(params[:page]).per(20)
  17 + merge_requests = merge_requests.includes(:author, :project).order("closed, created_at desc")
  18 +
  19 + # Filter by specific assignee_id (or lack thereof)?
  20 + if params[:assignee_id].present?
  21 + merge_requests = merge_requests.where(assignee_id: (params[:assignee_id] == '0' ? nil : params[:assignee_id]))
  22 + end
  23 +
  24 + # Filter by specific milestone_id (or lack thereof)?
  25 + if params[:milestone_id].present?
  26 + merge_requests = merge_requests.where(milestone_id: (params[:milestone_id] == '0' ? nil : params[:milestone_id]))
  27 + end
  28 +
  29 + merge_requests
15 end 30 end
16 end 31 end
app/contexts/search_context.rb
@@ -13,6 +13,7 @@ class SearchContext @@ -13,6 +13,7 @@ class SearchContext
13 result[:projects] = Project.where(id: project_ids).search(query).limit(10) 13 result[:projects] = Project.where(id: project_ids).search(query).limit(10)
14 result[:merge_requests] = MergeRequest.where(project_id: project_ids).search(query).limit(10) 14 result[:merge_requests] = MergeRequest.where(project_id: project_ids).search(query).limit(10)
15 result[:issues] = Issue.where(project_id: project_ids).search(query).limit(10) 15 result[:issues] = Issue.where(project_id: project_ids).search(query).limit(10)
  16 + result[:wiki_pages] = Wiki.where(project_id: project_ids).search(query).limit(10)
16 result 17 result
17 end 18 end
18 19
@@ -20,7 +21,8 @@ class SearchContext @@ -20,7 +21,8 @@ class SearchContext
20 @result ||= { 21 @result ||= {
21 projects: [], 22 projects: [],
22 merge_requests: [], 23 merge_requests: [],
23 - issues: [] 24 + issues: [],
  25 + wiki_pages: []
24 } 26 }
25 end 27 end
26 end 28 end
app/controllers/application_controller.rb
@@ -9,19 +9,28 @@ class ApplicationController &lt; ActionController::Base @@ -9,19 +9,28 @@ class ApplicationController &lt; ActionController::Base
9 helper_method :abilities, :can? 9 helper_method :abilities, :can?
10 10
11 rescue_from Gitlab::Gitolite::AccessDenied do |exception| 11 rescue_from Gitlab::Gitolite::AccessDenied do |exception|
  12 + log_exception(exception)
12 render "errors/gitolite", layout: "errors", status: 500 13 render "errors/gitolite", layout: "errors", status: 500
13 end 14 end
14 15
15 rescue_from Encoding::CompatibilityError do |exception| 16 rescue_from Encoding::CompatibilityError do |exception|
  17 + log_exception(exception)
16 render "errors/encoding", layout: "errors", status: 500 18 render "errors/encoding", layout: "errors", status: 500
17 end 19 end
18 20
19 rescue_from ActiveRecord::RecordNotFound do |exception| 21 rescue_from ActiveRecord::RecordNotFound do |exception|
  22 + log_exception(exception)
20 render "errors/not_found", layout: "errors", status: 404 23 render "errors/not_found", layout: "errors", status: 404
21 end 24 end
22 25
23 protected 26 protected
24 27
  28 + def log_exception(exception)
  29 + application_trace = ActionDispatch::ExceptionWrapper.new(env, exception).application_trace
  30 + application_trace.map!{ |t| " #{t}\n" }
  31 + logger.error "\n#{exception.class.name} (#{exception.message}):\n#{application_trace.join}"
  32 + end
  33 +
25 def reject_blocked! 34 def reject_blocked!
26 if current_user && current_user.blocked 35 if current_user && current_user.blocked
27 sign_out current_user 36 sign_out current_user
app/controllers/blob_controller.rb
1 # Controller for viewing a file's blame 1 # Controller for viewing a file's blame
2 class BlobController < ProjectResourceController 2 class BlobController < ProjectResourceController
3 include ExtractsPath 3 include ExtractsPath
4 - include Gitlab::Encode  
5 4
6 # Authorize 5 # Authorize
7 before_filter :authorize_read_project! 6 before_filter :authorize_read_project!
@@ -12,16 +11,9 @@ class BlobController &lt; ProjectResourceController @@ -12,16 +11,9 @@ class BlobController &lt; ProjectResourceController
12 11
13 def show 12 def show
14 if @tree.is_blob? 13 if @tree.is_blob?
15 - if @tree.text?  
16 - encoding = detect_encoding(@tree.data)  
17 - mime_type = encoding ? "text/plain; charset=#{encoding}" : "text/plain"  
18 - else  
19 - mime_type = @tree.mime_type  
20 - end  
21 -  
22 send_data( 14 send_data(
23 @tree.data, 15 @tree.data,
24 - type: mime_type, 16 + type: @tree.mime_type,
25 disposition: 'inline', 17 disposition: 'inline',
26 filename: @tree.name 18 filename: @tree.name
27 ) 19 )
app/controllers/dashboard_controller.rb
1 class DashboardController < ApplicationController 1 class DashboardController < ApplicationController
2 respond_to :html 2 respond_to :html
3 3
  4 + before_filter :event_filter, only: :index
  5 +
4 def index 6 def index
5 @groups = Group.where(id: current_user.projects.pluck(:group_id)) 7 @groups = Group.where(id: current_user.projects.pluck(:group_id))
6 @projects = current_user.projects_with_events 8 @projects = current_user.projects_with_events
7 @projects = @projects.page(params[:page]).per(30) 9 @projects = @projects.page(params[:page]).per(30)
8 10
9 - @events = Event.in_projects(current_user.project_ids).limit(20).offset(params[:offset] || 0) 11 + @events = Event.in_projects(current_user.project_ids)
  12 + @events = @event_filter.apply_filter(@events)
  13 + @events = @events.limit(20).offset(params[:offset] || 0)
  14 +
10 @last_push = current_user.recent_push 15 @last_push = current_user.recent_push
11 16
12 respond_to do |format| 17 respond_to do |format|
@@ -34,4 +39,8 @@ class DashboardController &lt; ApplicationController @@ -34,4 +39,8 @@ class DashboardController &lt; ApplicationController
34 format.atom { render layout: false } 39 format.atom { render layout: false }
35 end 40 end
36 end 41 end
  42 +
  43 + def event_filter
  44 + @event_filter ||= EventFilter.new(params[:event_filter])
  45 + end
37 end 46 end
app/controllers/milestones_controller.rb
@@ -31,7 +31,8 @@ class MilestonesController &lt; ProjectResourceController @@ -31,7 +31,8 @@ class MilestonesController &lt; ProjectResourceController
31 31
32 def show 32 def show
33 @issues = @milestone.issues 33 @issues = @milestone.issues
34 - @users = @milestone.participants 34 + @users = UserDecorator.decorate(@milestone.participants)
  35 + @merge_requests = @milestone.merge_requests
35 36
36 respond_to do |format| 37 respond_to do |format|
37 format.html 38 format.html
app/controllers/profile_controller.rb
@@ -22,7 +22,7 @@ class ProfileController &lt; ApplicationController @@ -22,7 +22,7 @@ class ProfileController &lt; ApplicationController
22 flash[:notice] = "Password was successfully updated. Please login with it" 22 flash[:notice] = "Password was successfully updated. Please login with it"
23 redirect_to new_user_session_path 23 redirect_to new_user_session_path
24 else 24 else
25 - render action: "password" 25 + render 'account'
26 end 26 end
27 end 27 end
28 28
app/controllers/projects_controller.rb
1 -require Rails.root.join('lib', 'gitlab', 'graph_commit') 1 +require Rails.root.join('lib', 'gitlab', 'graph', 'json_builder')
2 2
3 class ProjectsController < ProjectResourceController 3 class ProjectsController < ProjectResourceController
4 skip_before_filter :project, only: [:new, :create] 4 skip_before_filter :project, only: [:new, :create]
@@ -79,7 +79,9 @@ class ProjectsController &lt; ProjectResourceController @@ -79,7 +79,9 @@ class ProjectsController &lt; ProjectResourceController
79 end 79 end
80 80
81 def graph 81 def graph
82 - @days_json, @commits_json = Gitlab::GraphCommit.to_graph(project) 82 + graph = Gitlab::Graph::JsonBuilder.new(project)
  83 +
  84 + @days_json, @commits_json = graph.days_json, graph.commits_json
83 end 85 end
84 86
85 def destroy 87 def destroy
app/controllers/refs_controller.rb
1 class RefsController < ProjectResourceController 1 class RefsController < ProjectResourceController
2 - include Gitlab::Encode  
3 2
4 # Authorize 3 # Authorize
5 before_filter :authorize_read_project! 4 before_filter :authorize_read_project!
app/controllers/repositories_controller.rb
@@ -16,9 +16,14 @@ class RepositoriesController &lt; ProjectResourceController @@ -16,9 +16,14 @@ class RepositoriesController &lt; ProjectResourceController
16 @tags = @project.tags 16 @tags = @project.tags
17 end 17 end
18 18
  19 + def stats
  20 + @stats = Gitlab::GitStats.new(@project.repo, @project.root_ref)
  21 + @graph = @stats.graph
  22 + end
  23 +
19 def archive 24 def archive
20 unless can?(current_user, :download_code, @project) 25 unless can?(current_user, :download_code, @project)
21 - render_404 and return 26 + render_404 and return
22 end 27 end
23 28
24 29
app/controllers/search_controller.rb
@@ -5,5 +5,6 @@ class SearchController &lt; ApplicationController @@ -5,5 +5,6 @@ class SearchController &lt; ApplicationController
5 @projects = result[:projects] 5 @projects = result[:projects]
6 @merge_requests = result[:merge_requests] 6 @merge_requests = result[:merge_requests]
7 @issues = result[:issues] 7 @issues = result[:issues]
  8 + @wiki_pages = result[:wiki_pages]
8 end 9 end
9 end 10 end
app/controllers/tree_controller.rb
@@ -26,15 +26,14 @@ class TreeController &lt; ProjectResourceController @@ -26,15 +26,14 @@ class TreeController &lt; ProjectResourceController
26 end 26 end
27 27
28 def update 28 def update
29 - file_editor = Gitlab::FileEditor.new(current_user, @project, @ref)  
30 - update_status = file_editor.update(  
31 - @path, 29 + edit_file_action = Gitlab::Satellite::EditFileAction.new(current_user, @project, @ref, @path)
  30 + updated_successfully = edit_file_action.commit!(
32 params[:content], 31 params[:content],
33 params[:commit_message], 32 params[:commit_message],
34 params[:last_commit] 33 params[:last_commit]
35 ) 34 )
36 35
37 - if update_status 36 + if updated_successfully
38 redirect_to project_tree_path(@project, @id), notice: "Your changes have been successfully commited" 37 redirect_to project_tree_path(@project, @id), notice: "Your changes have been successfully commited"
39 else 38 else
40 flash[:notice] = "Your changes could not be commited, because the file has been changed" 39 flash[:notice] = "Your changes could not be commited, because the file has been changed"
app/decorators/commit_decorator.rb
@@ -47,21 +47,15 @@ class CommitDecorator &lt; ApplicationDecorator @@ -47,21 +47,15 @@ class CommitDecorator &lt; ApplicationDecorator
47 # Otherwise it will link to the author email as specified in the commit. 47 # Otherwise it will link to the author email as specified in the commit.
48 # 48 #
49 # options: 49 # options:
50 - # avatar: true will prepend avatar image  
51 - def author_link(options)  
52 - text = if options[:avatar]  
53 - avatar = h.image_tag h.gravatar_icon(author_email), class: "avatar", width: 16  
54 - "#{avatar} #{author_name}"  
55 - else  
56 - author_name  
57 - end  
58 - team_member = @project.try(:team_member_by_name_or_email, author_name, author_email) 50 + # avatar: true will prepend the avatar image
  51 + # size: size of the avatar image in px
  52 + def author_link(options = {})
  53 + person_link(options.merge source: :author)
  54 + end
59 55
60 - if team_member.nil?  
61 - h.mail_to author_email, text.html_safe, class: "commit-author-link"  
62 - else  
63 - h.link_to text, h.project_team_member_path(@project, team_member), class: "commit-author-link"  
64 - end 56 + # Just like #author_link but for the committer.
  57 + def committer_link(options = {})
  58 + person_link(options.merge source: :committer)
65 end 59 end
66 60
67 protected 61 protected
@@ -69,4 +63,30 @@ class CommitDecorator &lt; ApplicationDecorator @@ -69,4 +63,30 @@ class CommitDecorator &lt; ApplicationDecorator
69 def no_commit_message 63 def no_commit_message
70 "--no commit message" 64 "--no commit message"
71 end 65 end
  66 +
  67 + # Private: Returns a link to a person. If the person has a matching user and
  68 + # is a member of the current @project it will link to the team member page.
  69 + # Otherwise it will link to the person email as specified in the commit.
  70 + #
  71 + # options:
  72 + # source: one of :author or :committer
  73 + # avatar: true will prepend the avatar image
  74 + # size: size of the avatar image in px
  75 + def person_link(options = {})
  76 + source_name = send "#{options[:source]}_name".to_sym
  77 + source_email = send "#{options[:source]}_email".to_sym
  78 + text = if options[:avatar]
  79 + avatar = h.image_tag h.gravatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size]
  80 + %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>}
  81 + else
  82 + source_name
  83 + end
  84 + team_member = @project.try(:team_member_by_name_or_email, source_name, source_email)
  85 +
  86 + if team_member.nil?
  87 + h.mail_to source_email, text.html_safe, class: "commit-#{options[:source]}-link"
  88 + else
  89 + h.link_to text, h.project_team_member_path(@project, team_member), class: "commit-#{options[:source]}-link"
  90 + end
  91 + end
72 end 92 end
app/decorators/tree_decorator.rb
@@ -8,14 +8,14 @@ class TreeDecorator &lt; ApplicationDecorator @@ -8,14 +8,14 @@ class TreeDecorator &lt; ApplicationDecorator
8 8
9 #parts = parts[0...-1] if is_blob? 9 #parts = parts[0...-1] if is_blob?
10 10
11 - yield(h.link_to("..", "#", remote: true)) if parts.count > max_links 11 + yield(h.link_to("..", "#")) if parts.count > max_links
12 12
13 parts.each do |part| 13 parts.each do |part|
14 part_path = File.join(part_path, part) unless part_path.empty? 14 part_path = File.join(part_path, part) unless part_path.empty?
15 part_path = part if part_path.empty? 15 part_path = part if part_path.empty?
16 16
17 next unless parts.last(2).include?(part) if parts.count > max_links 17 next unless parts.last(2).include?(part) if parts.count > max_links
18 - yield(h.link_to(h.truncate(part, length: 40), h.project_tree_path(project, h.tree_join(ref, part_path)), remote: true)) 18 + yield(h.link_to(h.truncate(part, length: 40), h.project_tree_path(project, h.tree_join(ref, part_path))))
19 end 19 end
20 end 20 end
21 end 21 end
app/decorators/user_decorator.rb 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +class UserDecorator < ApplicationDecorator
  2 + decorates :user
  3 +
  4 + def avatar_image size = 16
  5 + h.image_tag h.gravatar_icon(self.email, size), class: "avatar #{"s#{size}"}", width: size
  6 + end
  7 +
  8 + def tm_of(project)
  9 + project.team_member_by_id(self.id)
  10 + end
  11 +end
app/helpers/application_helper.rb
@@ -36,7 +36,7 @@ module ApplicationHelper @@ -36,7 +36,7 @@ module ApplicationHelper
36 else 36 else
37 gravatar_prefix = request.ssl? ? "https://secure" : "http://www" 37 gravatar_prefix = request.ssl? ? "https://secure" : "http://www"
38 user_email.strip! 38 user_email.strip!
39 - "#{gravatar_prefix}.gravatar.com/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=identicon" 39 + "#{gravatar_prefix}.gravatar.com/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=mm"
40 end 40 end
41 end 41 end
42 42
app/helpers/commits_helper.rb
@@ -65,4 +65,9 @@ module CommitsHelper @@ -65,4 +65,9 @@ module CommitsHelper
65 end 65 end
66 end 66 end
67 67
  68 + def commit_to_html commit
  69 + if commit.model
  70 + escape_javascript(render 'commits/commit', commit: commit)
  71 + end
  72 + end
68 end 73 end
app/helpers/events_helper.rb
@@ -33,4 +33,22 @@ module EventsHelper @@ -33,4 +33,22 @@ module EventsHelper
33 image_tag event_image_path 33 image_tag event_image_path
34 end 34 end
35 end 35 end
  36 +
  37 + def event_filter_link key, tooltip
  38 + key = key.to_s
  39 +
  40 + filter = @event_filter.options key
  41 +
  42 + inactive = if @event_filter.active? key
  43 + nil
  44 + else
  45 + 'inactive'
  46 + end
  47 +
  48 + content_tag :div, class: "filter_icon #{inactive}" do
  49 + link_to dashboard_path(event_filter: filter), class: 'has_tooltip', 'data-original-title' => tooltip do
  50 + image_tag "event_filter_#{key}.png"
  51 + end
  52 + end
  53 + end
36 end 54 end
app/helpers/projects_helper.rb
@@ -10,5 +10,9 @@ module ProjectsHelper @@ -10,5 +10,9 @@ module ProjectsHelper
10 def link_to_project project 10 def link_to_project project
11 link_to project.name, project 11 link_to project.name, project
12 end 12 end
  13 +
  14 + def tm_path team_member
  15 + project_team_member_path(@project, team_member)
  16 + end
13 end 17 end
14 18
app/helpers/tree_helper.rb
@@ -67,4 +67,29 @@ module TreeHelper @@ -67,4 +67,29 @@ module TreeHelper
67 can?(current_user, :push_code, @project) 67 can?(current_user, :push_code, @project)
68 end 68 end
69 end 69 end
  70 +
  71 + # Breadcrumb links for a Project and, if applicable, a tree path
  72 + def breadcrumbs
  73 + return unless @project && @ref
  74 +
  75 + # Add the root project link and the arrow icon
  76 + crumbs = content_tag(:li) do
  77 + content_tag(:span, nil, class: 'arrow') +
  78 + link_to(@project.name, project_commits_path(@project, @ref))
  79 + end
  80 +
  81 + if @path
  82 + parts = @path.split('/')
  83 +
  84 + parts.each_with_index do |part, i|
  85 + crumbs += content_tag(:span, '/', class: 'divider')
  86 + crumbs += content_tag(:li) do
  87 + # The text is just the individual part, but the link needs all the parts before it
  88 + link_to part, project_commits_path(@project, tree_join(@ref, parts[0..i].join('/')))
  89 + end
  90 + end
  91 + end
  92 +
  93 + crumbs.html_safe
  94 + end
70 end 95 end
app/models/commit.rb
1 class Commit 1 class Commit
2 include ActiveModel::Conversion 2 include ActiveModel::Conversion
3 - include Gitlab::Encode  
4 include StaticModel 3 include StaticModel
5 extend ActiveModel::Naming 4 extend ActiveModel::Naming
6 5
  6 + # Safe amount of files with diffs in one commit to render
  7 + # Used to prevent 500 error on huge commits by suppressing diff
  8 + #
  9 + DIFF_SAFE_SIZE = 100
  10 +
7 attr_accessor :commit, :head, :refs 11 attr_accessor :commit, :head, :refs
8 12
9 delegate :message, :authored_date, :committed_date, :parents, :sha, 13 delegate :message, :authored_date, :committed_date, :parents, :sha,
@@ -107,7 +111,7 @@ class Commit @@ -107,7 +111,7 @@ class Commit
107 end 111 end
108 112
109 def safe_message 113 def safe_message
110 - @safe_message ||= utf8 message 114 + @safe_message ||= message
111 end 115 end
112 116
113 def created_at 117 def created_at
@@ -119,7 +123,7 @@ class Commit @@ -119,7 +123,7 @@ class Commit
119 end 123 end
120 124
121 def author_name 125 def author_name
122 - utf8 author.name 126 + author.name
123 end 127 end
124 128
125 # Was this commit committed by a different person than the original author? 129 # Was this commit committed by a different person than the original author?
@@ -128,7 +132,7 @@ class Commit @@ -128,7 +132,7 @@ class Commit
128 end 132 end
129 133
130 def committer_name 134 def committer_name
131 - utf8 committer.name 135 + committer.name
132 end 136 end
133 137
134 def committer_email 138 def committer_email
app/models/issue.rb
@@ -7,8 +7,6 @@ class Issue &lt; ActiveRecord::Base @@ -7,8 +7,6 @@ class Issue &lt; ActiveRecord::Base
7 7
8 acts_as_taggable_on :labels 8 acts_as_taggable_on :labels
9 9
10 - belongs_to :milestone  
11 -  
12 validates :description, length: { within: 0..2000 } 10 validates :description, length: { within: 0..2000 }
13 11
14 def self.open_for(user) 12 def self.open_for(user)
app/models/merge_request.rb
1 require Rails.root.join("app/models/commit") 1 require Rails.root.join("app/models/commit")
  2 +require Rails.root.join("app/roles/static_model")
2 3
3 class MergeRequest < ActiveRecord::Base 4 class MergeRequest < ActiveRecord::Base
4 include IssueCommonality 5 include IssueCommonality
5 include Votes 6 include Votes
6 7
7 - attr_accessible :title, :assignee_id, :closed, :target_branch, :source_branch, 8 + attr_accessible :title, :assignee_id, :closed, :target_branch, :source_branch, :milestone_id,
8 :author_id_of_changes 9 :author_id_of_changes
9 10
10 attr_accessor :should_remove_source_branch 11 attr_accessor :should_remove_source_branch
@@ -26,6 +27,10 @@ class MergeRequest &lt; ActiveRecord::Base @@ -26,6 +27,10 @@ class MergeRequest &lt; ActiveRecord::Base
26 where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) 27 where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name)
27 end 28 end
28 29
  30 + def self.find_all_by_milestone(milestone)
  31 + where("milestone_id = :milestone_id", milestone_id: milestone)
  32 + end
  33 +
29 def human_state 34 def human_state
30 states = { 35 states = {
31 CAN_BE_MERGED => "can_be_merged", 36 CAN_BE_MERGED => "can_be_merged",
@@ -60,7 +65,7 @@ class MergeRequest &lt; ActiveRecord::Base @@ -60,7 +65,7 @@ class MergeRequest &lt; ActiveRecord::Base
60 end 65 end
61 66
62 def check_if_can_be_merged 67 def check_if_can_be_merged
63 - self.state = if Gitlab::Merge.new(self, self.author).can_be_merged? 68 + self.state = if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged?
64 CAN_BE_MERGED 69 CAN_BE_MERGED
65 else 70 else
66 CANNOT_BE_MERGED 71 CANNOT_BE_MERGED
@@ -167,7 +172,7 @@ class MergeRequest &lt; ActiveRecord::Base @@ -167,7 +172,7 @@ class MergeRequest &lt; ActiveRecord::Base
167 end 172 end
168 173
169 def automerge!(current_user) 174 def automerge!(current_user)
170 - if Gitlab::Merge.new(self, current_user).merge! && self.unmerged_commits.empty? 175 + if Gitlab::Satellite::MergeAction.new(current_user, self).merge! && self.unmerged_commits.empty?
171 self.merge!(current_user.id) 176 self.merge!(current_user.id)
172 true 177 true
173 end 178 end
@@ -212,5 +217,6 @@ end @@ -212,5 +217,6 @@ end
212 # st_diffs :text(4294967295 217 # st_diffs :text(4294967295
213 # merged :boolean default(FALSE), not null 218 # merged :boolean default(FALSE), not null
214 # state :integer default(1), not null 219 # state :integer default(1), not null
  220 +# milestone_id :integer
215 # 221 #
216 222
app/models/milestone.rb
@@ -3,6 +3,7 @@ class Milestone &lt; ActiveRecord::Base @@ -3,6 +3,7 @@ class Milestone &lt; ActiveRecord::Base
3 3
4 belongs_to :project 4 belongs_to :project
5 has_many :issues 5 has_many :issues
  6 + has_many :merge_requests
6 7
7 validates :title, presence: true 8 validates :title, presence: true
8 validates :project, presence: true 9 validates :project, presence: true
@@ -15,8 +16,20 @@ class Milestone &lt; ActiveRecord::Base @@ -15,8 +16,20 @@ class Milestone &lt; ActiveRecord::Base
15 User.where(id: issues.pluck(:assignee_id)) 16 User.where(id: issues.pluck(:assignee_id))
16 end 17 end
17 18
  19 + def open_items_count
  20 + self.issues.opened.count + self.merge_requests.opened.count
  21 + end
  22 +
  23 + def closed_items_count
  24 + self.issues.closed.count + self.merge_requests.closed.count
  25 + end
  26 +
  27 + def total_items_count
  28 + self.issues.count + self.merge_requests.count
  29 + end
  30 +
18 def percent_complete 31 def percent_complete
19 - ((self.issues.closed.count * 100) / self.issues.count).abs 32 + ((closed_items_count * 100) / total_items_count).abs
20 rescue ZeroDivisionError 33 rescue ZeroDivisionError
21 100 34 100
22 end 35 end
app/models/note.rb
@@ -23,13 +23,13 @@ class Note &lt; ActiveRecord::Base @@ -23,13 +23,13 @@ class Note &lt; ActiveRecord::Base
23 mount_uploader :attachment, AttachmentUploader 23 mount_uploader :attachment, AttachmentUploader
24 24
25 # Scopes 25 # Scopes
26 - scope :common, where(noteable_id: nil)  
27 - scope :today, where("created_at >= :date", date: Date.today)  
28 - scope :last_week, where("created_at >= :date", date: (Date.today - 7.days)) 26 + scope :common, ->{ where(noteable_id: nil) }
  27 + scope :today, ->{ where("created_at >= :date", date: Date.today) }
  28 + scope :last_week, ->{ where("created_at >= :date", date: (Date.today - 7.days)) }
29 scope :since, ->(day) { where("created_at >= :date", date: (day)) } 29 scope :since, ->(day) { where("created_at >= :date", date: (day)) }
30 - scope :fresh, order("created_at ASC, id ASC")  
31 - scope :inc_author_project, includes(:project, :author)  
32 - scope :inc_author, includes(:author) 30 + scope :fresh, ->{ order("created_at ASC, id ASC") }
  31 + scope :inc_author_project, ->{ includes(:project, :author) }
  32 + scope :inc_author, ->{ includes(:author) }
33 33
34 def self.create_status_change_note(noteable, author, status) 34 def self.create_status_change_note(noteable, author, status)
35 create({ 35 create({
app/models/project.rb
@@ -104,8 +104,10 @@ class Project &lt; ActiveRecord::Base @@ -104,8 +104,10 @@ class Project &lt; ActiveRecord::Base
104 end 104 end
105 105
106 def repo_name 106 def repo_name
107 - if path == "gitolite-admin"  
108 - errors.add(:path, " like 'gitolite-admin' is not allowed") 107 + denied_paths = %w(gitolite-admin groups projects dashboard)
  108 +
  109 + if denied_paths.include?(path)
  110 + errors.add(:path, "like #{path} is not allowed")
109 end 111 end
110 end 112 end
111 113
app/models/tree.rb
@@ -8,7 +8,7 @@ class Tree @@ -8,7 +8,7 @@ class Tree
8 def initialize(raw_tree, project, ref = nil, path = nil) 8 def initialize(raw_tree, project, ref = nil, path = nil)
9 @project, @ref, @path = project, ref, path 9 @project, @ref, @path = project, ref, path
10 @tree = if path.present? 10 @tree = if path.present?
11 - raw_tree / path.dup.force_encoding('ascii-8bit') 11 + raw_tree / path
12 else 12 else
13 raw_tree 13 raw_tree
14 end 14 end
app/models/wiki.rb
@@ -15,6 +15,12 @@ class Wiki &lt; ActiveRecord::Base @@ -15,6 +15,12 @@ class Wiki &lt; ActiveRecord::Base
15 slug 15 slug
16 end 16 end
17 17
  18 + class << self
  19 + def search(query)
  20 + where("title like :query OR content like :query", query: "%#{query}%")
  21 + end
  22 + end
  23 +
18 protected 24 protected
19 25
20 def self.regenerate_from wiki 26 def self.regenerate_from wiki
app/roles/issue_commonality.rb
@@ -6,6 +6,7 @@ module IssueCommonality @@ -6,6 +6,7 @@ module IssueCommonality
6 belongs_to :project 6 belongs_to :project
7 belongs_to :author, class_name: "User" 7 belongs_to :author, class_name: "User"
8 belongs_to :assignee, class_name: "User" 8 belongs_to :assignee, class_name: "User"
  9 + belongs_to :milestone
9 has_many :notes, as: :noteable, dependent: :destroy 10 has_many :notes, as: :noteable, dependent: :destroy
10 11
11 validates :project, presence: true 12 validates :project, presence: true
app/roles/repository.rb
@@ -41,7 +41,7 @@ module Repository @@ -41,7 +41,7 @@ module Repository
41 end 41 end
42 42
43 def satellite 43 def satellite
44 - @satellite ||= Gitlab::Satellite.new(self) 44 + @satellite ||= Gitlab::Satellite::Satellite.new(self)
45 end 45 end
46 46
47 def has_post_receive_file? 47 def has_post_receive_file?
app/views/admin/projects/show.html.haml
@@ -43,7 +43,7 @@ @@ -43,7 +43,7 @@
43 %b 43 %b
44 Owner: 44 Owner:
45 %td 45 %td
46 - = @admin_project.owner.name 46 + = @admin_project.owner_name || '(deleted)'
47 %tr 47 %tr
48 %td 48 %td
49 %b 49 %b
app/views/admin/resque/show.html.haml
1 %h3.page_title Resque 1 %h3.page_title Resque
2 %br 2 %br
3 .ui-box 3 .ui-box
4 - %iframe{src: resque_url, width: '100%', height: 600, style: "border: none"} 4 + %iframe{src: resque_path, width: '100%', height: 600, style: "border: none"}
app/views/blame/_head.html.haml
@@ -4,7 +4,4 @@ @@ -4,7 +4,4 @@
4 = nav_link(controller: :refs) do 4 = nav_link(controller: :refs) do
5 = link_to 'Source', project_tree_path(@project, @ref) 5 = link_to 'Source', project_tree_path(@project, @ref)
6 %li.right 6 %li.right
7 - .input-prepend.project_clone_holder  
8 - %button{class: "btn small active", :"data-clone" => @project.ssh_url_to_repo} SSH  
9 - %button{class: "btn small", :"data-clone" => @project.http_url_to_repo}= Gitlab.config.web_protocol.upcase  
10 - = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select span5" 7 + = render "shared/clone_panel"
app/views/blame/show.html.haml
@@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
15 .file_title 15 .file_title
16 %i.icon-file 16 %i.icon-file
17 %span.file_name 17 %span.file_name
18 - = @tree.name.force_encoding('utf-8') 18 + = @tree.name
19 %small= number_to_human_size @tree.size 19 %small= number_to_human_size @tree.size
20 %span.options= render "tree/blob_actions" 20 %span.options= render "tree/blob_actions"
21 .file_content.blame 21 .file_content.blame
@@ -24,9 +24,7 @@ @@ -24,9 +24,7 @@
24 - commit = Commit.new(commit) 24 - commit = Commit.new(commit)
25 - commit = CommitDecorator.decorate(commit) 25 - commit = CommitDecorator.decorate(commit)
26 %tr 26 %tr
27 - %td.author  
28 - = image_tag gravatar_icon(commit.author_email, 16)  
29 - = commit.author_name 27 + %td.author= commit.author_link avatar: true, size: 16
30 %td.blame_commit 28 %td.blame_commit
31 &nbsp; 29 &nbsp;
32 %code= link_to commit.short_id, project_commit_path(@project, commit) 30 %code= link_to commit.short_id, project_commit_path(@project, commit)
@@ -34,4 +32,4 @@ @@ -34,4 +32,4 @@
34 %td.lines 32 %td.lines
35 = preserve do 33 = preserve do
36 %pre 34 %pre
37 - = Gitlab::Encode.utf8 lines.join("\n") 35 + = lines.join("\n")
app/views/commit/huge_commit.html.haml 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 += render "commits/commit_box"
  2 +.alert-message.block-message.error
  3 + %h4 Commit diffs are too big to be displayed
app/views/commits/_commit.html.haml
@@ -4,9 +4,8 @@ @@ -4,9 +4,8 @@
4 %strong= link_to "Browse Code »", project_tree_path(@project, commit), class: "right" 4 %strong= link_to "Browse Code »", project_tree_path(@project, commit), class: "right"
5 %p 5 %p
6 = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id" 6 = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id"
7 - %strong.commit-author-name= commit.author_name  
8 - %span.dash &ndash;  
9 - = image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16 7 + = commit.author_link avatar: true, size: 24
  8 + &nbsp;
10 = link_to_gfm truncate(commit.title, length: 50), project_commit_path(@project, commit.id), class: "row_title" 9 = link_to_gfm truncate(commit.title, length: 50), project_commit_path(@project, commit.id), class: "row_title"
11 10
12 %span.committed_ago 11 %span.committed_ago
app/views/commits/_commit_box.html.haml
@@ -18,16 +18,15 @@ @@ -18,16 +18,15 @@
18 .commit-info 18 .commit-info
19 .row 19 .row
20 .span5 20 .span5
21 - = image_tag gravatar_icon(@commit.author_email, 40), class: "avatar"  
22 .author 21 .author
23 - %strong= @commit.author_name 22 + %strong= @commit.author_link avatar: true, size: 40
24 authored 23 authored
25 %time{title: @commit.authored_date.stamp("Aug 21, 2011 9:23pm")} 24 %time{title: @commit.authored_date.stamp("Aug 21, 2011 9:23pm")}
26 #{time_ago_in_words(@commit.authored_date)} ago 25 #{time_ago_in_words(@commit.authored_date)} ago
27 - if @commit.different_committer? 26 - if @commit.different_committer?
28 .committer 27 .committer
29 &rarr; 28 &rarr;
30 - %strong= @commit.committer_name 29 + %strong= @commit.committer_link
31 committed 30 committed
32 %time{title: @commit.committed_date.stamp("Aug 21, 2011 9:23pm")} 31 %time{title: @commit.committed_date.stamp("Aug 21, 2011 9:23pm")}
33 #{time_ago_in_words(@commit.committed_date)} ago 32 #{time_ago_in_words(@commit.committed_date)} ago
app/views/commits/_diffs.html.haml
1 - if @suppress_diff 1 - if @suppress_diff
2 .alert-message.block-message 2 .alert-message.block-message
3 %p 3 %p
4 - %strong Warning! Large commit with more then 200 files changed. 4 + %strong Warning! Large commit with more then #{Commit::DIFF_SAFE_SIZE} files changed.
5 %p To prevent performance issue we rejected diff information. 5 %p To prevent performance issue we rejected diff information.
6 %p 6 %p
7 But if you still want to see diff 7 But if you still want to see diff
8 - = link_to "click this link", project_commit_path(@project, @commit, force_show_diff: true), class: "dark" 8 + = link_to "click this link", project_commit_path(@project, @commit, force_show_diff: true), class: "underlined_link"
9 9
10 %p.cgray 10 %p.cgray
11 Showing #{pluralize(diffs.count, "changed file")} 11 Showing #{pluralize(diffs.count, "changed file")}
@@ -35,10 +35,10 @@ @@ -35,10 +35,10 @@
35 - if file.text? 35 - if file.text?
36 = render "commits/text_file", diff: diff, index: i 36 = render "commits/text_file", diff: diff, index: i
37 - elsif file.image? 37 - elsif file.image?
38 - - if diff.renamed_file || diff.new_file || diff.deleted_file 38 + - if diff.renamed_file || diff.new_file || diff.deleted_file
39 .diff_file_content_image 39 .diff_file_content_image
40 %img{class: image_diff_class(diff), src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} 40 %img{class: image_diff_class(diff), src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"}
41 - - else 41 + - else
42 - old_file = (@commit.prev_commit.tree / diff.old_path) 42 - old_file = (@commit.prev_commit.tree / diff.old_path)
43 .diff_file_content_image.img_compared 43 .diff_file_content_image.img_compared
44 %img{class: "diff_image_removed", src: "data:#{file.mime_type};base64,#{Base64.encode64(old_file.data)}"} 44 %img{class: "diff_image_removed", src: "data:#{file.mime_type};base64,#{Base64.encode64(old_file.data)}"}
app/views/commits/_head.html.haml
@@ -16,6 +16,11 @@ @@ -16,6 +16,11 @@
16 Tags 16 Tags
17 %span.badge= @project.tags.length 17 %span.badge= @project.tags.length
18 18
  19 + = nav_link(controller: :repositories, action: :stats) do
  20 + = link_to stats_project_repository_path(@project) do
  21 + Stats
  22 +
  23 +
19 - if current_controller?(:commits) && current_user.private_token 24 - if current_controller?(:commits) && current_user.private_token
20 %li.right 25 %li.right
21 %span.rss-icon 26 %span.rss-icon
app/views/commits/huge_commit.html.haml
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
1 -= render "commits/commit_box"  
2 -.alert-message.block-message.error  
3 - %h4 Commit diffs are too big to be displayed  
app/views/commits/show.html.haml
@@ -2,14 +2,7 @@ @@ -2,14 +2,7 @@
2 2
3 - if @path.present? 3 - if @path.present?
4 %ul.breadcrumb 4 %ul.breadcrumb
5 - %li  
6 - %span.arrow  
7 - = link_to project_commits_path(@project) do  
8 - = @project.name  
9 - %span.divider  
10 - \/  
11 - %li  
12 - %a{href: "#"}= @path.split("/").join(" / ") 5 + = breadcrumbs
13 6
14 %div{id: dom_id(@project)} 7 %div{id: dom_id(@project)}
15 #commits_list= render "commits" 8 #commits_list= render "commits"
app/views/dashboard/index.html.haml
@@ -3,10 +3,17 @@ @@ -3,10 +3,17 @@
3 .activities.span8 3 .activities.span8
4 = render "events/event_last_push", event: @last_push 4 = render "events/event_last_push", event: @last_push
5 = render 'shared/no_ssh' 5 = render 'shared/no_ssh'
  6 +
  7 + .event_filter
  8 + = event_filter_link EventFilter.push, 'Push events'
  9 + = event_filter_link EventFilter.merged, 'Merge events'
  10 + = event_filter_link EventFilter.comments, 'Comments'
  11 + = event_filter_link EventFilter.team, 'Team'
  12 +
6 - if @events.any? 13 - if @events.any?
7 .content_list= render @events 14 .content_list= render @events
8 - else 15 - else
9 - %h4.nothing_here_message Projects activity will be displayed here 16 + %p.nothing_here_message Projects activity will be displayed here
10 .loading.hide 17 .loading.hide
11 .side 18 .side
12 - if @groups.present? 19 - if @groups.present?
app/views/devise/sessions/new.html.haml
@@ -14,8 +14,9 @@ @@ -14,8 +14,9 @@
14 = f.submit "Sign in", :class => "primary btn wide" 14 = f.submit "Sign in", :class => "primary btn wide"
15 .right 15 .right
16 = render :partial => "devise/shared/links" 16 = render :partial => "devise/shared/links"
17 - - if devise_mapping.omniauthable?  
18 - %hr/  
19 - - resource_class.omniauth_providers.each do |provider|  
20 - %span  
21 - = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider) 17 + .clearfix
  18 + - if devise_mapping.omniauthable? && resource_class.omniauth_providers.present?
  19 + %div
  20 + - resource_class.omniauth_providers.each do |provider|
  21 + %span
  22 + = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider)
app/views/help/system_hooks.html.haml
@@ -5,9 +5,10 @@ @@ -5,9 +5,10 @@
5 %hr 5 %hr
6 6
7 %p.slead 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. 8 + Your GitLab instance can perform HTTP POST requests on the following events: create_project, delete_project, create_user, delete_user, change_team_member.
9 %br 9 %br
10 - System Hooks can be used for logging or change information in LDAP server. 10 + %br
  11 + System Hooks can be used, e.g. for logging or changing information in a LDAP server.
11 %br 12 %br
12 %h5 Hooks request example: 13 %h5 Hooks request example:
13 = render "admin/hooks/data_ex" 14 = render "admin/hooks/data_ex"
app/views/issues/_form.html.haml
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@
12 = f.label :title do 12 = f.label :title do
13 %strong= "Subject *" 13 %strong= "Subject *"
14 .input 14 .input
15 - = f.text_field :title, maxlength: 255, class: "xxlarge gfm-input", autofocus: true 15 + = f.text_field :title, maxlength: 255, class: "xxlarge js-gfm-input", autofocus: true
16 .issue_middle_block 16 .issue_middle_block
17 .issue_assignee 17 .issue_assignee
18 = f.label :assignee_id do 18 = f.label :assignee_id do
@@ -37,7 +37,7 @@ @@ -37,7 +37,7 @@
37 .clearfix 37 .clearfix
38 = f.label :description, "Details" 38 = f.label :description, "Details"
39 .input 39 .input
40 - = f.text_area :description, maxlength: 2000, class: "xxlarge gfm-input", rows: 14 40 + = f.text_area :description, maxlength: 2000, class: "xxlarge js-gfm-input", rows: 14
41 %p.hint Issues are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}. 41 %p.hint Issues are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
42 42
43 43
app/views/issues/edit.js.haml
1 :plain 1 :plain
2 - var edit_issue_dialog = $("<div id='edit_issue_dialog'></div>");  
3 - edit_issue_dialog.html("#{escape_javascript(render('form'))}");  
4 - switchToEditIssue(edit_issue_dialog); 2 + $("#edit_issue_dialog").html("#{escape_javascript(render('form'))}");
  3 + switchToEditIssue();
5 4
app/views/issues/index.html.haml
@@ -58,6 +58,8 @@ @@ -58,6 +58,8 @@
58 %ul#issues-table.unstyled.issues_table 58 %ul#issues-table.unstyled.issues_table
59 = render "issues" 59 = render "issues"
60 60
  61 +#new_issue_dialog
  62 +#edit_issue_dialog
61 63
62 :javascript 64 :javascript
63 $(function(){ 65 $(function(){
app/views/issues/new.js.haml
1 :plain 1 :plain
2 - var new_issue_dialog = $("<div id='new_issue_dialog'></div>");  
3 - new_issue_dialog.html("#{escape_javascript(render('form'))}");  
4 - switchToNewIssue(new_issue_dialog); 2 + $("#new_issue_dialog").html("#{escape_javascript(render('form'))}");
  3 + switchToNewIssue();
app/views/layouts/_head_panel.html.haml
@@ -8,9 +8,7 @@ @@ -8,9 +8,7 @@
8 GITLAB 8 GITLAB
9 %span.separator 9 %span.separator
10 %h1.project_name= title 10 %h1.project_name= title
11 - .search  
12 - = form_tag search_path, method: :get do |f|  
13 - = text_field_tag "search", nil, placeholder: "Search", class: "search-input" 11 + = render "layouts/search"
14 .fbtn 12 .fbtn
15 - if current_user.is_admin? 13 - if current_user.is_admin?
16 = link_to admin_root_path, class: "btn small", title: "Admin area" do 14 = link_to admin_root_path, class: "btn small", title: "Admin area" do
@@ -29,11 +27,3 @@ @@ -29,11 +27,3 @@
29 = link_to 'Logout', destroy_user_session_path, class: "logout", method: :delete 27 = link_to 'Logout', destroy_user_session_path, class: "logout", method: :delete
30 28
31 = render "layouts/init_auto_complete" 29 = render "layouts/init_auto_complete"
32 -  
33 -:javascript  
34 - $(function(){  
35 - $("#search").autocomplete({  
36 - source: #{raw search_autocomplete_source},  
37 - select: function(event, ui) { location.href = ui.item.url }  
38 - });  
39 - });  
app/views/layouts/_init_auto_complete.html.haml
1 :javascript 1 :javascript
2 $(function() { 2 $(function() {
3 - autocompleteMembersUrl = "#{ "/api/v2/projects/#{@project.code}/members" if @project }";  
4 - autocompleteMembersParams.private_token = "#{current_user.authentication_token}"; 3 + autocompleteMembers.url = "#{ "/api/v2/projects/#{@project.code}/members" if @project }";
  4 + autocompleteMembers.params.private_token = "#{current_user.private_token}";
5 5
6 - autocompleteEmojiData = #{raw emoji_autocomplete_source}; 6 + autocompleteEmoji.data = #{raw emoji_autocomplete_source};
7 // convert the list so that the items have the right format for completion 7 // convert the list so that the items have the right format for completion
8 - autocompleteEmojiData = $.map(autocompleteEmojiData, function(value) { 8 + autocompleteEmoji.data = $.map(autocompleteEmoji.data, function(value) {
9 return { 9 return {
10 name: value, 10 name: value,
11 insert: value+':', 11 insert: value+':',
app/views/layouts/_search.html.haml 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +.search
  2 + = form_tag search_path, method: :get do |f|
  3 + = text_field_tag "search", nil, placeholder: "Search", class: "search-input"
  4 +
  5 +:javascript
  6 + $(function(){
  7 + $("#search").autocomplete({
  8 + source: #{raw search_autocomplete_source},
  9 + select: function(event, ui) { location.href = ui.item.url }
  10 + });
  11 + });
app/views/merge_requests/_form.html.haml
@@ -28,16 +28,22 @@ @@ -28,16 +28,22 @@
28 %h4.cdark 2. Fill info 28 %h4.cdark 2. Fill info
29 29
30 .clearfix 30 .clearfix
31 - .main_box 31 + .merge_requests_form_box
32 .top_box_content 32 .top_box_content
33 - = f.label :title do 33 + = f.label :title do
34 %strong= "Title *" 34 %strong= "Title *"
35 - .input= f.text_field :title, class: "input-xxlarge pad gfm-input", maxlength: 255, rows: 5  
36 - .middle_box_content  
37 - = f.label :assignee_id do  
38 - %i.icon-user  
39 - Assign to  
40 - .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, {class: 'chosen span3'}) 35 + .input= f.text_field :title, class: "input-xxlarge pad js-gfm-input", maxlength: 255, rows: 5
  36 + .merge_requests_middle_box
  37 + .merge_requests_assignee
  38 + = f.label :assignee_id do
  39 + %i.icon-user
  40 + Assign to
  41 + .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, {class: 'chosen span3'})
  42 + .merge_requests_milestone
  43 + = f.label :milestone_id do
  44 + %i.icon-time
  45 + Milestone
  46 + .input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }, {class: 'chosen'})
41 47
42 .control-group 48 .control-group
43 49
app/views/merge_requests/_merge_request.html.haml
@@ -10,6 +10,10 @@ @@ -10,6 +10,10 @@
10 %span.btn.small.disabled.grouped 10 %span.btn.small.disabled.grouped
11 %i.icon-comment 11 %i.icon-comment
12 = merge_request.mr_and_commit_notes.count 12 = merge_request.mr_and_commit_notes.count
  13 + - if merge_request.milestone_id?
  14 + %span.btn.small.disabled.grouped
  15 + %i.icon-time
  16 + = merge_request.milestone.title
13 %span.btn.small.disabled.grouped 17 %span.btn.small.disabled.grouped
14 = merge_request.source_branch 18 = merge_request.source_branch
15 &rarr; 19 &rarr;
app/views/merge_requests/branch_from.js.haml
1 :plain 1 :plain
2 - $(".mr_source_commit").html("#{escape_javascript(render 'commits/commit', commit: @commit)}"); 2 + $(".mr_source_commit").html("#{commit_to_html(@commit)}");
app/views/merge_requests/branch_to.js.haml
1 :plain 1 :plain
2 - $(".mr_target_commit").html("#{escape_javascript(render 'commits/commit', commit: @commit)}");  
3 - 2 + $(".mr_target_commit").html("#{commit_to_html(@commit)}");
app/views/merge_requests/index.html.haml
@@ -9,19 +9,26 @@ @@ -9,19 +9,26 @@
9 9
10 .ui-box 10 .ui-box
11 .title 11 .title
12 - %ul.nav.nav-pills  
13 - %li{class: ("active" if (params[:f] == 'open' || !params[:f]))}  
14 - = link_to project_merge_requests_path(@project, f: 'open') do  
15 - Open  
16 - %li{class: ("active" if params[:f] == "closed")}  
17 - = link_to project_merge_requests_path(@project, f: "closed") do  
18 - Closed  
19 - %li{class: ("active" if params[:f] == 'assigned-to-me')}  
20 - = link_to project_merge_requests_path(@project, f: 'assigned-to-me') do  
21 - To Me  
22 - %li{class: ("active" if params[:f] == 'all')}  
23 - = link_to project_merge_requests_path(@project, f: 'all') do  
24 - All 12 + .left
  13 + %ul.nav.nav-pills
  14 + %li{class: ("active" if (params[:f] == 'open' || !params[:f]))}
  15 + = link_to project_merge_requests_path(@project, f: 'open', milestone_id: params[:milestone_id]) do
  16 + Open
  17 + %li{class: ("active" if params[:f] == "closed")}
  18 + = link_to project_merge_requests_path(@project, f: "closed", milestone_id: params[:milestone_id]) do
  19 + Closed
  20 + %li{class: ("active" if params[:f] == 'assigned-to-me')}
  21 + = link_to project_merge_requests_path(@project, f: 'assigned-to-me', milestone_id: params[:milestone_id]) do
  22 + To Me
  23 + %li{class: ("active" if params[:f] == 'all')}
  24 + = link_to project_merge_requests_path(@project, f: 'all', milestone_id: params[:milestone_id]) do
  25 + All
  26 + .right
  27 + = form_tag project_merge_requests_path(@project), id: "merge_requests_search_form", method: :get, class: :right do
  28 + = select_tag(:assignee_id, options_from_collection_for_select([unassigned_filter] + @project.users.all, "id", "name", params[:assignee_id]), prompt: "Assignee")
  29 + = select_tag(:milestone_id, options_from_collection_for_select([unassigned_filter] + @project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), prompt: "Milestone")
  30 + = hidden_field_tag :f, params[:f]
  31 + .clearfix
25 32
26 %ul.unstyled 33 %ul.unstyled
27 = render @merge_requests 34 = render @merge_requests
@@ -35,3 +42,7 @@ @@ -35,3 +42,7 @@
35 .span4.right 42 .span4.right
36 %span.cgray.right #{@merge_requests.total_count} merge requests for this filter 43 %span.cgray.right #{@merge_requests.total_count} merge requests for this filter
37 44
  45 +:javascript
  46 + $(function() {
  47 + merge_requestsPage();
  48 + })
app/views/merge_requests/show/_mr_box.html.haml
@@ -14,9 +14,13 @@ @@ -14,9 +14,13 @@
14 %strong.author= link_to_merge_request_author(@merge_request) 14 %strong.author= link_to_merge_request_author(@merge_request)
15 15
16 - if @merge_request.assignee 16 - if @merge_request.assignee
17 - %cite.cgray and currently assigned to 17 + %cite.cgray , currently assigned to
18 = image_tag gravatar_icon(@merge_request.assignee_email), width: 16, class: "lil_av" 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 %strong.author= link_to_merge_request_assignee(@merge_request)
  20 + - if @merge_request.milestone
  21 + - milestone = @merge_request.milestone
  22 + %cite.cgray and attached to milestone
  23 + %strong= link_to_gfm truncate(milestone.title, length: 20), project_milestone_path(milestone.project, milestone)
20 24
21 25
22 - if @merge_request.closed 26 - if @merge_request.closed
app/views/milestones/_milestone.html.haml
1 %li{class: "milestone", id: dom_id(milestone) } 1 %li{class: "milestone", id: dom_id(milestone) }
2 .right 2 .right
3 - - if milestone.issues.any?  
4 - %span.btn.small.disabled.grouped= pluralize milestone.issues.count, 'issues'  
5 - - if milestone.issues.count > 0  
6 - = link_to 'Browse Issues', project_issues_path(milestone.project, milestone_id: milestone.id), class: "btn small grouped"  
7 - if can? current_user, :admin_milestone, milestone.project 3 - if can? current_user, :admin_milestone, milestone.project
8 - = link_to 'Edit', edit_project_milestone_path(milestone.project, milestone), class: "btn small edit-milestone-link grouped" 4 + = link_to edit_project_milestone_path(milestone.project, milestone), class: "btn small edit-milestone-link grouped" do
  5 + %i.icon-edit
  6 + Edit
9 %h4 7 %h4
10 - = link_to_gfm truncate(milestone.title, length: 100), project_milestone_path(milestone.project, milestone), class: "row_title" 8 + = link_to_gfm truncate(milestone.title, length: 100), project_milestone_path(milestone.project, milestone)
11 %small 9 %small
12 = milestone.expires_at 10 = milestone.expires_at
13 - %br  
14 - .progress.progress-success.span3  
15 - .bar{style: "width: #{milestone.percent_complete}%;"}  
16 -  
17 -  
18 - &nbsp; 11 + .row
  12 + .span4
  13 + .progress.progress-info
  14 + .bar{style: "width: #{milestone.percent_complete}%;"}
  15 + .span6
  16 + = link_to project_issues_path(milestone.project, milestone_id: milestone.id) do
  17 + = pluralize milestone.issues.count, 'Issue'
  18 + &nbsp;
  19 + = link_to project_merge_requests_path(milestone.project, milestone_id: milestone.id) do
  20 + = pluralize milestone.merge_requests.count, 'Merge Request'
  21 + &nbsp;
  22 + %span.light #{milestone.percent_complete}% complete
app/views/milestones/show.html.haml
@@ -31,10 +31,10 @@ @@ -31,10 +31,10 @@
31 %h5 31 %h5
32 Progress: 32 Progress:
33 %small 33 %small
34 - #{@milestone.issues.closed.count} closed 34 + #{@milestone.closed_items_count} closed
35 &ndash; 35 &ndash;
36 - #{@milestone.issues.opened.count} open  
37 - .progress.progress-success 36 + #{@milestone.open_items_count} open
  37 + .progress.progress-info
38 .bar{style: "width: #{@milestone.percent_complete}%;"} 38 .bar{style: "width: #{@milestone.percent_complete}%;"}
39 39
40 40
@@ -58,15 +58,28 @@ @@ -58,15 +58,28 @@
58 %span.badge.badge-info ##{issue.id} 58 %span.badge.badge-info ##{issue.id}
59 &ndash; 59 &ndash;
60 = link_to_gfm truncate(issue.title, length: 60), [@project, issue] 60 = link_to_gfm truncate(issue.title, length: 60), [@project, issue]
61 - %br  
62 61
63 .span6 62 .span6
64 - %table 63 + %table.milestone-merge-requests-filter
65 %thead 64 %thead
66 - %th Participants  
67 - - @users.each do |user|  
68 - %tr 65 + %th
  66 + %ul.nav.nav-pills
  67 + %li.active= link_to('Open Merge Requests', '#')
  68 + %li=link_to('All Merge Requests', '#')
  69 + - @merge_requests.each do |merge_request|
  70 + %tr{data: {closed: merge_request.closed}}
69 %td 71 %td
70 - = image_tag gravatar_icon(user.email, 24), width: "24"  
71 - &nbsp;  
72 - = user.name 72 + = link_to [@project, merge_request] do
  73 + %span.badge.badge-info ##{merge_request.id}
  74 + &ndash;
  75 + = link_to_gfm truncate(merge_request.title, length: 60), [@project, merge_request]
  76 +
  77 +%hr
  78 +%h6 Participants:
  79 +%div
  80 + - @users.each do |user|
  81 + = link_to tm_path(user.tm_of(@project)), class: 'float-link' do
  82 + = user.avatar_image
  83 + = user.name
  84 +
  85 +.clearfix
app/views/notes/_common_form.html.haml
@@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
8 8
9 = f.hidden_field :noteable_id 9 = f.hidden_field :noteable_id
10 = f.hidden_field :noteable_type 10 = f.hidden_field :noteable_type
11 - = f.text_area :note, size: 255, class: 'note-text gfm-input' 11 + = f.text_area :note, size: 255, class: 'note-text js-gfm-input'
12 #preview-note.preview_note.hide 12 #preview-note.preview_note.hide
13 .hint 13 .hint
14 .right Comments are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}. 14 .right Comments are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
app/views/notes/_per_line_form.html.haml
@@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@
13 = f.hidden_field :noteable_id 13 = f.hidden_field :noteable_id
14 = f.hidden_field :noteable_type 14 = f.hidden_field :noteable_type
15 = f.hidden_field :line_code 15 = f.hidden_field :line_code
16 - = f.text_area :note, size: 255, class: 'line-note-text gfm-input' 16 + = f.text_area :note, size: 255, class: 'line-note-text js-gfm-input'
17 .note_actions 17 .note_actions
18 .buttons 18 .buttons
19 = f.submit 'Add note', class: "btn save-btn submit_note submit_inline_note", id: "submit_note" 19 = f.submit 'Add note', class: "btn save-btn submit_note submit_inline_note", id: "submit_note"
app/views/notify/project_access_granted_email.html.haml
@@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
4 %td{style: "font-size: 1px; line-height: 1px;", width: "21"} 4 %td{style: "font-size: 1px; line-height: 1px;", width: "21"}
5 %td{align: "left", style: "padding: 20px 0 0;"} 5 %td{align: "left", style: "padding: 20px 0 0;"}
6 %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} 6 %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
7 - = "You got granted #{@users_project.project_access_human} access to project" 7 + = "You have been granted #{@users_project.project_access_human} access to project"
8 %td{style: "font-size: 1px; line-height: 1px;", width: "21"} 8 %td{style: "font-size: 1px; line-height: 1px;", width: "21"}
9 %tr 9 %tr
10 %td{style: "font-size: 1px; line-height: 1px;", width: "21"} 10 %td{style: "font-size: 1px; line-height: 1px;", width: "21"}