Merge branch 'master' into discussions
Conflicts: app/assets/stylesheets/main.scss app/models/project.rb app/views/notes/_common_form.html.haml app/views/notes/_per_line_form.html.haml lib/gitlab/markdown.rb spec/models/note_spec.rb
|  | @ -1,4 +1,5 @@ | ||||||
| env: | env: | ||||||
|  |   - DB=postgresql | ||||||
|   - DB=mysql |   - DB=mysql | ||||||
| before_install: | before_install: | ||||||
|   - sudo apt-get install libicu-dev -y |   - sudo apt-get install libicu-dev -y | ||||||
|  | @ -18,8 +19,7 @@ services: | ||||||
| before_script: | before_script: | ||||||
|   - "cp config/database.yml.$DB config/database.yml" |   - "cp config/database.yml.$DB config/database.yml" | ||||||
|   - "cp config/gitlab.yml.example config/gitlab.yml" |   - "cp config/gitlab.yml.example config/gitlab.yml" | ||||||
|   - "bundle exec rake db:create RAILS_ENV=test" |   - "bundle exec rake db:setup RAILS_ENV=test" | ||||||
|   - "bundle exec rake db:migrate RAILS_ENV=test" |  | ||||||
|   - "bundle exec rake db:seed_fu RAILS_ENV=test" |   - "bundle exec rake db:seed_fu RAILS_ENV=test" | ||||||
|   - "sh -e /etc/init.d/xvfb start" |   - "sh -e /etc/init.d/xvfb start" | ||||||
| script: "bundle exec rake travis --trace" | script: "bundle exec rake travis --trace" | ||||||
|  |  | ||||||
							
								
								
									
										11
									
								
								CHANGELOG
								
								
								
								
							
							
						
						|  | @ -1,4 +1,15 @@ | ||||||
| v 4.0.0 | v 4.0.0 | ||||||
|  |   - Reorganized settings | ||||||
|  |   - Fixed commits compare | ||||||
|  |   - Refactored scss | ||||||
|  |   - Improve status checks | ||||||
|  |   - Validates presence of User#name | ||||||
|  |   - Fixed postgres support | ||||||
|  |   - Removed sqlite support | ||||||
|  |   - Modified post-receive hook | ||||||
|  |   - Milestones can be closed now | ||||||
|  |   - Show comment events on dashboard | ||||||
|  |   - Quick add team members via group#people page | ||||||
|   - [API] expose created date for hooks and SSH keys |   - [API] expose created date for hooks and SSH keys | ||||||
|   - [API] list, create issue notes |   - [API] list, create issue notes | ||||||
|   - [API] list, create snippet notes |   - [API] list, create snippet notes | ||||||
|  |  | ||||||
|  | @ -1,26 +1,26 @@ | ||||||
| ## Contribute to GitLab | # Contact & support | ||||||
| 
 | 
 | ||||||
| If you want to contribute to GitLab, follow this process: | If you want quick help, head over to our [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq). | ||||||
|  | Otherwise you can follow our [Issue Submission Guide](https://github.com/gitlabhq/gitlabhq/wiki/Issue-Submission-Guide) for a more systematic and thorough guide to solving your issues. | ||||||
| 
 | 
 | ||||||
| 1. Fork the project |  | ||||||
| 2. Create a feature branch |  | ||||||
| 3. Code |  | ||||||
| 4. Create a pull request |  | ||||||
| 
 | 
 | ||||||
| We will only accept pull requests if: |  | ||||||
| 
 | 
 | ||||||
| * Your code has proper tests and all tests pass | # Contribute to GitLab | ||||||
| * Your code can be merged w/o problems |  | ||||||
| * It won't break existing functionality |  | ||||||
| * It's quality code |  | ||||||
| * We like it :) |  | ||||||
| 
 | 
 | ||||||
| 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). | ## Recipes | ||||||
| 
 | 
 | ||||||
| ## Installation | We collect user submitted installation scripts and config file templates for platforms we don't support officially. | ||||||
|  | We believe there is merit in allowing a certain amount of diversity. | ||||||
|  | You can get and submit your solution to running/configuring GitLab with your favorite OS/distro, database, web server, cloud hoster, configuration management tool, etc. | ||||||
| 
 | 
 | ||||||
| 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. | Help us improve the collection of [GitLab Recipes](https://github.com/gitlabhq/gitlab-recipes/) | ||||||
| 
 | 
 | ||||||
| ## Running tests |  | ||||||
| 
 | 
 | ||||||
| For more information on running the tests please read the [development tips](https://github.com/gitlabhq/gitlabhq/blob/master/doc/development.md) | ## Feature suggestions | ||||||
|  | 
 | ||||||
|  | Follow the [Issue Submission Guide](https://github.com/gitlabhq/gitlabhq/wiki/Issue-Submission-Guide) and support other peoples ideas or propose your own. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ## Code | ||||||
|  | 
 | ||||||
|  | Follow our [Developer Guide](https://github.com/gitlabhq/gitlabhq/wiki/Developer-Guide) to set you up for hacking on GitLab. | ||||||
|  |  | ||||||
							
								
								
									
										6
									
								
								Gemfile
								
								
								
								
							
							
						
						|  | @ -32,7 +32,7 @@ gem 'grit_ext',      git: "https://github.com/gitlabhq/grit_ext.git",       ref: | ||||||
| gem "gitolite", '1.1.0' | gem "gitolite", '1.1.0' | ||||||
| 
 | 
 | ||||||
| # Syntax highlighter | # Syntax highlighter | ||||||
| gem "pygments.rb",  git: "https://github.com/gitlabhq/pygments.rb.git", ref: '4db80c599067e2d5f23c5c243bf85b8ca0368ad4' | gem "pygments.rb",  git: "https://github.com/gitlabhq/pygments.rb.git", branch: "master" | ||||||
| 
 | 
 | ||||||
| # Language detection | # Language detection | ||||||
| gem "github-linguist", "~> 2.3.4" , require: "linguist" | gem "github-linguist", "~> 2.3.4" , require: "linguist" | ||||||
|  | @ -100,7 +100,7 @@ group :assets do | ||||||
|   gem "therubyracer" |   gem "therubyracer" | ||||||
| 
 | 
 | ||||||
|   gem 'chosen-rails',     "0.9.8" |   gem 'chosen-rails',     "0.9.8" | ||||||
|   gem 'jquery-atwho-rails', "0.1.6" |   gem 'jquery-atwho-rails', "0.1.7" | ||||||
|   gem "jquery-rails",     "2.1.3" |   gem "jquery-rails",     "2.1.3" | ||||||
|   gem "jquery-ui-rails",  "2.0.2" |   gem "jquery-ui-rails",  "2.0.2" | ||||||
|   gem "modernizr",        "2.6.2" |   gem "modernizr",        "2.6.2" | ||||||
|  | @ -124,7 +124,7 @@ group :development, :test do | ||||||
|   gem "capybara" |   gem "capybara" | ||||||
|   gem "pry" |   gem "pry" | ||||||
|   gem "awesome_print" |   gem "awesome_print" | ||||||
|   gem "database_cleaner" |   gem "database_cleaner", ref: "f89c34300e114be99532f14c115b2799a3380ac6", git: "https://github.com/bmabey/database_cleaner.git" | ||||||
|   gem "launchy" |   gem "launchy" | ||||||
|   gem 'factory_girl_rails' |   gem 'factory_girl_rails' | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										18
									
								
								Gemfile.lock
								
								
								
								
							
							
						
						|  | @ -1,3 +1,10 @@ | ||||||
|  | GIT | ||||||
|  |   remote: https://github.com/bmabey/database_cleaner.git | ||||||
|  |   revision: f89c34300e114be99532f14c115b2799a3380ac6 | ||||||
|  |   ref: f89c34300e114be99532f14c115b2799a3380ac6 | ||||||
|  |   specs: | ||||||
|  |     database_cleaner (0.9.1) | ||||||
|  | 
 | ||||||
| GIT | GIT | ||||||
|   remote: https://github.com/ctran/annotate_models.git |   remote: https://github.com/ctran/annotate_models.git | ||||||
|   revision: be4e26825b521f0b2d86b181e2dff89901aa9b1e |   revision: be4e26825b521f0b2d86b181e2dff89901aa9b1e | ||||||
|  | @ -45,8 +52,8 @@ GIT | ||||||
| 
 | 
 | ||||||
| GIT | GIT | ||||||
|   remote: https://github.com/gitlabhq/pygments.rb.git |   remote: https://github.com/gitlabhq/pygments.rb.git | ||||||
|   revision: 4db80c599067e2d5f23c5c243bf85b8ca0368ad4 |   revision: db1da0343adf86b49bdc3add04d02d2e80438d38 | ||||||
|   ref: 4db80c599067e2d5f23c5c243bf85b8ca0368ad4 |   branch: master | ||||||
|   specs: |   specs: | ||||||
|     pygments.rb (0.3.2) |     pygments.rb (0.3.2) | ||||||
|       posix-spawn (~> 0.3.6) |       posix-spawn (~> 0.3.6) | ||||||
|  | @ -140,7 +147,6 @@ GEM | ||||||
|     colorize (0.5.8) |     colorize (0.5.8) | ||||||
|     crack (0.3.1) |     crack (0.3.1) | ||||||
|     daemons (1.1.9) |     daemons (1.1.9) | ||||||
|     database_cleaner (0.9.1) |  | ||||||
|     devise (2.1.2) |     devise (2.1.2) | ||||||
|       bcrypt-ruby (~> 3.0) |       bcrypt-ruby (~> 3.0) | ||||||
|       orm_adapter (~> 0.1) |       orm_adapter (~> 0.1) | ||||||
|  | @ -227,7 +233,7 @@ GEM | ||||||
|     httpauth (0.2.0) |     httpauth (0.2.0) | ||||||
|     i18n (0.6.1) |     i18n (0.6.1) | ||||||
|     journey (1.0.4) |     journey (1.0.4) | ||||||
|     jquery-atwho-rails (0.1.6) |     jquery-atwho-rails (0.1.7) | ||||||
|     jquery-rails (2.1.3) |     jquery-rails (2.1.3) | ||||||
|       railties (>= 3.1.0, < 5.0) |       railties (>= 3.1.0, < 5.0) | ||||||
|       thor (~> 0.14) |       thor (~> 0.14) | ||||||
|  | @ -458,7 +464,7 @@ DEPENDENCIES | ||||||
|   chosen-rails (= 0.9.8) |   chosen-rails (= 0.9.8) | ||||||
|   coffee-rails (~> 3.2.2) |   coffee-rails (~> 3.2.2) | ||||||
|   colored |   colored | ||||||
|   database_cleaner |   database_cleaner! | ||||||
|   devise (~> 2.1.0) |   devise (~> 2.1.0) | ||||||
|   draper (~> 0.18.0) |   draper (~> 0.18.0) | ||||||
|   email_spec |   email_spec | ||||||
|  | @ -481,7 +487,7 @@ DEPENDENCIES | ||||||
|   guard-spinach |   guard-spinach | ||||||
|   haml-rails (~> 0.3.5) |   haml-rails (~> 0.3.5) | ||||||
|   httparty |   httparty | ||||||
|   jquery-atwho-rails (= 0.1.6) |   jquery-atwho-rails (= 0.1.7) | ||||||
|   jquery-rails (= 2.1.3) |   jquery-rails (= 2.1.3) | ||||||
|   jquery-ui-rails (= 2.0.2) |   jquery-ui-rails (= 2.0.2) | ||||||
|   kaminari (~> 0.14.1) |   kaminari (~> 0.14.1) | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| # Welcome to GitLab [](https://secure.travis-ci.org/gitlabhq/gitlabhq) [](https://secure.travis-ci.org/gitlabhq/grit) [](https://codeclimate.com/github/gitlabhq/gitlabhq) | # Welcome to GitLab [](https://travis-ci.org/gitlabhq/gitlabhq) [](https://travis-ci.org/gitlabhq/grit) [](https://codeclimate.com/github/gitlabhq/gitlabhq) [](https://gemnasium.com/gitlabhq/gitlabhq) | ||||||
| 
 | 
 | ||||||
| GitLab is a free project and repository management application | GitLab is a free project and repository management application | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
| After Width: | Height: | Size: 8.2 KiB | 
| Before Width: | Height: | Size: 2.9 KiB | 
| Before Width: | Height: | Size: 3.2 KiB | 
| Before Width: | Height: | Size: 4.5 KiB | 
| Before Width: | Height: | Size: 3.2 KiB | 
| Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.9 KiB | 
| Before Width: | Height: | Size: 2.1 KiB | 
| Before Width: | Height: | Size: 2.3 KiB | 
| After Width: | Height: | Size: 1.2 KiB | 
|  | @ -1,52 +1,38 @@ | ||||||
| # Creates the variables for setting up GFM auto-completion | # Creates the variables for setting up GFM auto-completion | ||||||
| 
 | 
 | ||||||
| window.GitLab ?= {} | window.GitLab ?= {} | ||||||
| GitLab.GfmAutoComplete ?= {} | GitLab.GfmAutoComplete = | ||||||
| 
 |  | ||||||
| # Emoji |  | ||||||
| data      = [] |  | ||||||
| template  = "<li data-value='${insert}'>${name} <img alt='${name}' height='20' src='${image}' width='20' /></li>" |  | ||||||
| GitLab.GfmAutoComplete.Emoji = {data, template} |  | ||||||
| 
 |  | ||||||
| # Team Members |  | ||||||
| data      = [] |  | ||||||
| url     = ''; |  | ||||||
| params  = {private_token: '', page: 1} |  | ||||||
| GitLab.GfmAutoComplete.Members = {data, url, params} |  | ||||||
| 
 |  | ||||||
| # Add GFM auto-completion to all input fields, that accept GFM input. |  | ||||||
| GitLab.GfmAutoComplete.setup = -> |  | ||||||
|   input = $('.js-gfm-input') |  | ||||||
| 
 |  | ||||||
|   # Emoji |   # Emoji | ||||||
|   input.atWho ':', |   Emoji: | ||||||
|     data: GitLab.GfmAutoComplete.Emoji.data, |     data: [] | ||||||
|     tpl: GitLab.GfmAutoComplete.Emoji.template |     template: '<li data-value="${insert}">${name} <img alt="${name}" height="20" src="${image}" width="20" /></li>' | ||||||
| 
 | 
 | ||||||
|   # Team Members |   # Team Members | ||||||
|   input.atWho '@', (query, callback) -> |   Members: | ||||||
|     (getMoreMembers = -> |     data: [] | ||||||
|       $.getJSON(GitLab.GfmAutoComplete.Members.url, GitLab.GfmAutoComplete.Members.params) |     url: '' | ||||||
|         .success (members) -> |     params: | ||||||
|           # pick the data we need |       private_token: '' | ||||||
|           newMembersData = $.map(members, (m) -> m.name ) |     template: '<li data-value="${username}">${username} <small>${name}</small></li>' | ||||||
| 
 | 
 | ||||||
|           # add the new page of data to the rest |   # Add GFM auto-completion to all input fields, that accept GFM input. | ||||||
|           $.merge(GitLab.GfmAutoComplete.Members.data, newMembersData) |   setup: -> | ||||||
|  |     input = $('.js-gfm-input') | ||||||
| 
 | 
 | ||||||
|           # show the pop-up with a copy of the current data |     # Emoji | ||||||
|           callback(GitLab.GfmAutoComplete.Members.data[..]) |     input.atWho ':', | ||||||
|  |       data: @Emoji.data | ||||||
|  |       tpl: @Emoji.template | ||||||
| 
 | 
 | ||||||
|           # are we past the last page? |     # Team Members | ||||||
|           if newMembersData.length is 0 |     input.atWho '@', | ||||||
|             # set static data and stop callbacks |       tpl: @Members.template | ||||||
|             input.atWho '@', |       callback: (query, callback) => | ||||||
|               data: GitLab.GfmAutoComplete.Members.data |         request_params = $.extend({}, @Members.params, query: query) | ||||||
|               callback: null |         $.getJSON(@Members.url, request_params).done (members) => | ||||||
|           else |           new_members_data = $.map(members, (m) -> | ||||||
|             # get next page |             username: m.username, | ||||||
|             getMoreMembers() |             name: m.name | ||||||
|  |           ) | ||||||
|  |           callback(new_members_data) | ||||||
| 
 | 
 | ||||||
|       # so the next request gets the next page |  | ||||||
|       GitLab.GfmAutoComplete.Members.params.page += 1 |  | ||||||
|     ).call() |  | ||||||
|  |  | ||||||
|  | @ -1,43 +1,3 @@ | ||||||
| function switchToNewIssue(){ |  | ||||||
|   $(".issues_content").hide("fade", { direction: "left" }, 150, function(){ |  | ||||||
|     $('select#issue_assignee_id').chosen(); |  | ||||||
|     $('select#issue_milestone_id').chosen(); |  | ||||||
|     $("#new_issue_dialog").show("fade", { direction: "right" }, 150); |  | ||||||
|     $('.top-tabs .add_new').hide(); |  | ||||||
|     disableButtonIfEmptyField("#issue_title", ".save-btn"); |  | ||||||
|     GitLab.GfmAutoComplete.setup(); |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function switchToEditIssue(){ |  | ||||||
|   $(".issues_content").hide("fade", { direction: "left" }, 150, function(){ |  | ||||||
|     $('select#issue_assignee_id').chosen(); |  | ||||||
|     $('select#issue_milestone_id').chosen(); |  | ||||||
|     $("#edit_issue_dialog").show("fade", { direction: "right" }, 150); |  | ||||||
|     $('.add_new').hide(); |  | ||||||
|     disableButtonIfEmptyField("#issue_title", ".save-btn"); |  | ||||||
|     GitLab.GfmAutoComplete.setup(); |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function switchFromNewIssue(){ |  | ||||||
|   backToIssues(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function switchFromEditIssue(){ |  | ||||||
|   backToIssues(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function backToIssues(){ |  | ||||||
|   $("#edit_issue_dialog, #new_issue_dialog").hide("fade", { direction: "right" }, 150, function(){ |  | ||||||
|     $(".issues_content").show("fade", { direction: "left" }, 150, function() {  |  | ||||||
|       $("#edit_issue_dialog").html(""); |  | ||||||
|       $("#new_issue_dialog").html(""); |  | ||||||
|       $('.add_new').show(); |  | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function initIssuesSearch() {  | function initIssuesSearch() {  | ||||||
|   var href       = $('#issue_search_form').attr('action'); |   var href       = $('#issue_search_form').attr('action'); | ||||||
|   var last_terms = ''; |   var last_terms = ''; | ||||||
|  | @ -76,23 +36,15 @@ function issuesPage(){ | ||||||
|     $(this).closest("form").submit(); |     $(this).closest("form").submit(); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   $("#new_issue_link").click(function(){ |   $('body').on('ajax:success', '.close_issue, .reopen_issue', function(){ | ||||||
|     updateNewIssueURL(); |  | ||||||
|   }); |  | ||||||
| 
 |  | ||||||
|   $('body').on('ajax:success', '.close_issue, .reopen_issue, #new_issue', function(){ |  | ||||||
|     var t = $(this), |     var t = $(this), | ||||||
|         totalIssues, |         totalIssues, | ||||||
|         reopen = t.hasClass('reopen_issue'), |         reopen = t.hasClass('reopen_issue'); | ||||||
|         newIssue = false; |     $('.issue_counter').each(function(){ | ||||||
|     if( this.id == 'new_issue' ){ |  | ||||||
|       newIssue = true; |  | ||||||
|     } |  | ||||||
|     $('.issue_counter, #new_issue').each(function(){ |  | ||||||
|       var issue = $(this); |       var issue = $(this); | ||||||
|       totalIssues = parseInt( $(this).html(), 10 ); |       totalIssues = parseInt( $(this).html(), 10 ); | ||||||
| 
 | 
 | ||||||
|       if( newIssue || ( reopen && issue.closest('.main_menu').length ) ){ |       if( reopen && issue.closest('.main_menu').length ){ | ||||||
|         $(this).html( totalIssues+1 ); |         $(this).html( totalIssues+1 ); | ||||||
|       }else { |       }else { | ||||||
|         $(this).html( totalIssues-1 ); |         $(this).html( totalIssues-1 ); | ||||||
|  | @ -126,20 +78,3 @@ function issuesCheckChanged() { | ||||||
|     $('.issues_filters').show(); |     $('.issues_filters').show(); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| function updateNewIssueURL(){ |  | ||||||
|   var new_issue_link = $("#new_issue_link"); |  | ||||||
|   var milestone_id = $("#milestone_id").val(); |  | ||||||
|   var assignee_id = $("#assignee_id").val(); |  | ||||||
|   var new_href = ""; |  | ||||||
|   if(milestone_id){ |  | ||||||
|     new_href = "issue[milestone_id]=" + milestone_id + "&"; |  | ||||||
|   } |  | ||||||
|   if(assignee_id){ |  | ||||||
|     new_href = new_href + "issue[assignee_id]=" + assignee_id; |  | ||||||
|   } |  | ||||||
|   if(new_href.length){ |  | ||||||
|     new_href = new_issue_link.attr("href") + "?" + new_href; |  | ||||||
|     new_issue_link.attr("href", new_href); |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  | @ -7,6 +7,18 @@ window.slugify = (text) -> | ||||||
| window.ajaxGet = (url) -> | window.ajaxGet = (url) -> | ||||||
|   $.ajax({type: "GET", url: url, dataType: "script"}) |   $.ajax({type: "GET", url: url, dataType: "script"}) | ||||||
| 
 | 
 | ||||||
|  | window.errorMessage = (message) -> | ||||||
|  |   ehtml = $("<p>") | ||||||
|  |   ehtml.addClass("error_message") | ||||||
|  |   ehtml.html(message) | ||||||
|  |   ehtml | ||||||
|  | 
 | ||||||
|  | window.split = (val) -> | ||||||
|  |   return val.split( /,\s*/ ) | ||||||
|  | 
 | ||||||
|  | window.extractLast = (term) -> | ||||||
|  |   return split( term ).pop() | ||||||
|  | 
 | ||||||
| # Disable button if text field is empty | # Disable button if text field is empty | ||||||
| window.disableButtonIfEmptyField = (field_selector, button_selector) -> | window.disableButtonIfEmptyField = (field_selector, button_selector) -> | ||||||
|   field = $(field_selector) |   field = $(field_selector) | ||||||
|  |  | ||||||
|  | @ -26,6 +26,12 @@ var MergeRequest = { | ||||||
|           self.showState(data.state); |           self.showState(data.state); | ||||||
|         }, "json"); |         }, "json"); | ||||||
|       } |       } | ||||||
|  | 
 | ||||||
|  |       if(self.opts.ci_enable){ | ||||||
|  |         $.get(self.opts.url_to_ci_check, function(data){ | ||||||
|  |           self.showCiState(data.status); | ||||||
|  |         }, "json"); | ||||||
|  |       } | ||||||
|     }, |     }, | ||||||
| 
 | 
 | ||||||
|   initTabs: |   initTabs: | ||||||
|  | @ -79,6 +85,11 @@ var MergeRequest = { | ||||||
|       $(".automerge_widget." + state).show(); |       $(".automerge_widget." + state).show(); | ||||||
|     }, |     }, | ||||||
| 
 | 
 | ||||||
|  |   showCiState: | ||||||
|  |     function(state){ | ||||||
|  |       $(".ci_widget").hide(); | ||||||
|  |       $(".ci_widget.ci-" + state).show(); | ||||||
|  |     }, | ||||||
| 
 | 
 | ||||||
|   loadDiff: |   loadDiff: | ||||||
|     function() {  |     function() {  | ||||||
|  |  | ||||||
|  | @ -18,10 +18,3 @@ $ -> | ||||||
|   # Ref switcher |   # Ref switcher | ||||||
|   $('.project-refs-select').on 'change', -> |   $('.project-refs-select').on 'change', -> | ||||||
|     $(@).parents('form').submit() |     $(@).parents('form').submit() | ||||||
| 
 |  | ||||||
| class @GraphNav |  | ||||||
|   @init: -> |  | ||||||
|     $('.graph svg').css 'position', 'relative' |  | ||||||
|     $('body').bind 'keyup', (e) -> |  | ||||||
|       $('.graph svg').animate(left: '+=400') if e.keyCode is 37 # left |  | ||||||
|       $('.graph svg').animate(left: '-=400') if e.keyCode is 39 # right |  | ||||||
|  |  | ||||||
|  | @ -1,10 +0,0 @@ | ||||||
| /* |  | ||||||
|  * This is a manifest file that'll automatically include all the stylesheets available in this directory |  | ||||||
|  * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at |  | ||||||
|  * the top of the compiled file, but it's generally better to create a new file per style scope. |  | ||||||
|  *= require jquery.ui.gitlab |  | ||||||
|  *= require jquery.atwho |  | ||||||
|  *= require chosen |  | ||||||
|  *= require_self |  | ||||||
|  *= require main |  | ||||||
| */ |  | ||||||
|  | @ -0,0 +1,52 @@ | ||||||
|  | /* | ||||||
|  |  * This is a manifest file that'll automatically include all the stylesheets available in this directory | ||||||
|  |  * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at | ||||||
|  |  * the top of the compiled file, but it's generally better to create a new file per style scope. | ||||||
|  |  *= require jquery.ui.gitlab | ||||||
|  |  *= require jquery.atwho | ||||||
|  |  *= require chosen | ||||||
|  |  *= require_self | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * GitLab bootstrap: | ||||||
|  |  */ | ||||||
|  | @import "gitlab_bootstrap.scss"; | ||||||
|  | 
 | ||||||
|  | @import "common.scss"; | ||||||
|  | @import "ref_select.scss"; | ||||||
|  | 
 | ||||||
|  | @import "sections/header.scss"; | ||||||
|  | @import "sections/nav.scss"; | ||||||
|  | @import "sections/commits.scss"; | ||||||
|  | @import "sections/issues.scss"; | ||||||
|  | @import "sections/projects.scss"; | ||||||
|  | @import "sections/snippets.scss"; | ||||||
|  | @import "sections/votes.scss"; | ||||||
|  | @import "sections/merge_requests.scss"; | ||||||
|  | @import "sections/graph.scss"; | ||||||
|  | @import "sections/events.scss"; | ||||||
|  | @import "sections/themes.scss"; | ||||||
|  | @import "sections/tree.scss"; | ||||||
|  | @import "sections/notes.scss"; | ||||||
|  | @import "sections/profile.scss"; | ||||||
|  | @import "sections/login.scss"; | ||||||
|  | @import "sections/editor.scss"; | ||||||
|  | 
 | ||||||
|  | @import "highlight/white.scss"; | ||||||
|  | @import "highlight/dark.scss"; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * UI themes: | ||||||
|  |  */ | ||||||
|  | @import "themes/ui_basic.scss"; | ||||||
|  | @import "themes/ui_mars.scss"; | ||||||
|  | @import "themes/ui_modern.scss"; | ||||||
|  | @import "themes/ui_gray.scss"; | ||||||
|  | @import "themes/ui_color.scss"; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Styles for JS behaviors. | ||||||
|  |  */ | ||||||
|  | @import "behaviors.scss"; | ||||||
|  | 
 | ||||||
|  | @ -13,20 +13,12 @@ body { | ||||||
|   margin: 0 0; |   margin: 0 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .container  .sidebar { |  | ||||||
|   width: 200px; |  | ||||||
|   height: 100%; |  | ||||||
|   min-height: 450px; |  | ||||||
|   float: right; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| .visible_link, | .visible_link, | ||||||
| .author_link { | .author_link { | ||||||
|   color: $link_color; |   color: $link_color; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .help li { color:#111 } | .help li { color:$style_color; } | ||||||
| 
 | 
 | ||||||
| .back_link { | .back_link { | ||||||
|   text-decoration: underline; |   text-decoration: underline; | ||||||
|  | @ -65,6 +57,9 @@ table a code { | ||||||
|   background: url(ajax_loader.gif) no-repeat center center; |   background: url(ajax_loader.gif) no-repeat center center; | ||||||
|   width: 40px; |   width: 40px; | ||||||
|   height: 40px; |   height: 40px; | ||||||
|  |   &.loading-gray { | ||||||
|  |     background: url(ajax_loader_gray.gif) no-repeat center center; | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** FLASH message **/ | /** FLASH message **/ | ||||||
|  | @ -96,28 +91,17 @@ table a code { | ||||||
|   margin-right:50px |   margin-right:50px | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .handle:hover { |  | ||||||
|   cursor: move; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| span.update-author { | span.update-author { | ||||||
|   display: block; |   display: block; | ||||||
| } |  | ||||||
| span.update-author { |  | ||||||
|   color: #999; |   color: #999; | ||||||
|   font-weight: normal; |   font-weight: normal; | ||||||
|   font-style: italic; |   font-style: italic; | ||||||
| } |   strong { | ||||||
| span.update-author strong { |     font-weight: bold; | ||||||
|   font-weight: bold; |     font-style: normal; | ||||||
|   font-style: normal; |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** UPDATE ITEM **/ |  | ||||||
| span.update-author { |  | ||||||
|   display: block; |  | ||||||
| } |  | ||||||
| /** END UPDATE ITEM **/ |  | ||||||
| .dashboard-loader { | .dashboard-loader { | ||||||
|   float: left; |   float: left; | ||||||
|   margin: 10px; |   margin: 10px; | ||||||
|  | @ -264,21 +248,6 @@ input.git_clone_url { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /** bordered list **/ |  | ||||||
| ul.bordered-list { |  | ||||||
|   margin: 5px 0px; |  | ||||||
|   padding: 0px; |  | ||||||
|   li { |  | ||||||
|     padding: 5px 0; |  | ||||||
|     border-bottom: 1px solid #EEE; |  | ||||||
|     overflow: hidden; |  | ||||||
|     display: block; |  | ||||||
|     margin: 0px; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| ul.bordered-list li:last-child { border:none } |  | ||||||
| 
 |  | ||||||
| .line_holder { | .line_holder { | ||||||
|   &:hover { |   &:hover { | ||||||
|     td { |     td { | ||||||
|  | @ -316,98 +285,6 @@ p.time { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| .ico { |  | ||||||
|   background: url("images.png") no-repeat -85px -77px; |  | ||||||
|   width: 19px; |  | ||||||
|   height: 16px; |  | ||||||
|   float: left; |  | ||||||
|   position: relative; |  | ||||||
|   margin-right: 10px; |  | ||||||
|   top: 8px; |  | ||||||
| 
 |  | ||||||
|   &.project { |  | ||||||
|     background-position:  -37px -77px; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   &.activities { |  | ||||||
|     background-position:-162px -22px; |  | ||||||
|   } |  | ||||||
|   &.projects { |  | ||||||
|     background-position:-209px -21px; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .leftbar { |  | ||||||
|   h5, .title { |  | ||||||
|     padding: 5px 10px; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   h4 { |  | ||||||
|     font-size: 14px; |  | ||||||
|     padding: 2px 10px; |  | ||||||
|     color: #666; |  | ||||||
|     border-bottom: 1px solid #f1f1f1; |  | ||||||
|   } |  | ||||||
|   a:last-child h4 { border: none; } |  | ||||||
| 
 |  | ||||||
|   a:hover { |  | ||||||
|     h4 { |  | ||||||
|       color: #111; |  | ||||||
|       background: $hover; |  | ||||||
|       border-color: #CCC; |  | ||||||
|       .ico.project { |  | ||||||
|         background-position:-209px -21px; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   .bottom { |  | ||||||
|     padding: 10px; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .votes { |  | ||||||
|   font-size: 13px; |  | ||||||
|   line-height: 15px; |  | ||||||
|   .progress { |  | ||||||
|     height: 4px; |  | ||||||
|     margin: 0; |  | ||||||
|     .bar { |  | ||||||
|       float: left; |  | ||||||
|       height: 100%; |  | ||||||
|     } |  | ||||||
|     .bar-success { |  | ||||||
|       @include linear-gradient(#62C462, #51A351); |  | ||||||
|       background-color: #468847; |  | ||||||
|     } |  | ||||||
|     .bar-danger { |  | ||||||
|       @include linear-gradient(#EE5F5B, #BD362F); |  | ||||||
|       background-color: #B94A48; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   .upvotes { |  | ||||||
|     display: inline-block; |  | ||||||
|     color: #468847; |  | ||||||
|   } |  | ||||||
|   .downvotes { |  | ||||||
|     display: inline-block; |  | ||||||
|     color: #B94A48; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| .votes-block { |  | ||||||
|   margin: 14px 6px 6px 0; |  | ||||||
|   .downvotes { |  | ||||||
|     float: right; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| .votes-inline { |  | ||||||
|   display: inline-block; |  | ||||||
|   margin: 0 8px; |  | ||||||
|   .progress { |  | ||||||
|     display: inline-block; |  | ||||||
|     padding: 0 0 2px; |  | ||||||
|     width: 45px; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| /* Fix for readme code (stopped it from being yellow) */ | /* Fix for readme code (stopped it from being yellow) */ | ||||||
| .readme { | .readme { | ||||||
|  | @ -420,7 +297,6 @@ p.time { | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| .highlight_word { | .highlight_word { | ||||||
|   background: #EEDC94; |   background: #EEDC94; | ||||||
| } | } | ||||||
|  | @ -428,23 +304,16 @@ p.time { | ||||||
| .status_info { | .status_info { | ||||||
|   font-size: 14px; |   font-size: 14px; | ||||||
|   padding: 5px 15px; |   padding: 5px 15px; | ||||||
|   line-height: 24px; |   line-height: 26px; | ||||||
|   width: 60px; |  | ||||||
|   text-align: center; |   text-align: center; | ||||||
|   float: left; |   float: right; | ||||||
|   margin-right: 20px; |   position: relative; | ||||||
|  |   top: -5px; | ||||||
|  |   @include border-radius(4px); | ||||||
| 
 | 
 | ||||||
|   &.success { |  | ||||||
|     background: #5BB75B; |  | ||||||
|     color: white; |  | ||||||
|     text-shadow: 0 1px #111; |  | ||||||
|     border-color: #9A9; |  | ||||||
|   } |  | ||||||
|   &.error { |   &.error { | ||||||
|     background: #DA4E49; |     background: #DA4E49; | ||||||
|     border-color: #BD362F; |     color: #FFF; | ||||||
|     color: white; |  | ||||||
|     text-shadow: 0 1px #111; |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -463,16 +332,6 @@ p.time { | ||||||
|   height: 150px; |   height: 150px; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .gitlab_pagination { |  | ||||||
|   span a { color: $link_color; } |  | ||||||
|   .prev, .next, .current, .page a { |  | ||||||
|     padding: 10px; |  | ||||||
|   } |  | ||||||
|   .current { |  | ||||||
|     border-bottom: 2px solid $style_color; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Fixes alignment on notes. | // Fixes alignment on notes. | ||||||
| .new_note { | .new_note { | ||||||
|   label { |   label { | ||||||
|  | @ -647,9 +506,14 @@ pre { | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .milestone .progress { | .milestone { | ||||||
|   margin-bottom: 0; |   &.milestone-closed { | ||||||
|   margin-top: 4px; |     background: #eee; | ||||||
|  |   } | ||||||
|  |   .progress { | ||||||
|  |     margin-bottom: 0; | ||||||
|  |     margin-top: 4px; | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .float-link { | .float-link { | ||||||
|  |  | ||||||
|  | @ -0,0 +1,26 @@ | ||||||
|  | /** Override bootstrap variables **/ | ||||||
|  | $baseFontSize: 13px !default; | ||||||
|  | $baseLineHeight: 18px !default; | ||||||
|  | 
 | ||||||
|  | // BOOTSTRAP | ||||||
|  | @import "bootstrap"; | ||||||
|  | @import "bootstrap/responsive-utilities"; | ||||||
|  | @import "bootstrap/responsive-1200px-min"; | ||||||
|  | 
 | ||||||
|  | @import "font-awesome"; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * GitLab bootstrap. | ||||||
|  |  * Overrides some styles of twitter bootstrap. | ||||||
|  |  * Also give some common classes for GitLab app | ||||||
|  |  */ | ||||||
|  | @import "gitlab_bootstrap/variables.scss"; | ||||||
|  | @import "gitlab_bootstrap/fonts.scss"; | ||||||
|  | @import "gitlab_bootstrap/mixins.scss"; | ||||||
|  | @import "gitlab_bootstrap/common.scss"; | ||||||
|  | @import "gitlab_bootstrap/typography.scss"; | ||||||
|  | @import "gitlab_bootstrap/buttons.scss"; | ||||||
|  | @import "gitlab_bootstrap/blocks.scss"; | ||||||
|  | @import "gitlab_bootstrap/files.scss"; | ||||||
|  | @import "gitlab_bootstrap/tables.scss"; | ||||||
|  | @import "gitlab_bootstrap/lists.scss"; | ||||||
|  | @ -31,6 +31,7 @@ | ||||||
|   .middle_box_content, |   .middle_box_content, | ||||||
|   .bottom_box_content { |   .bottom_box_content { | ||||||
|     padding: 15px; |     padding: 15px; | ||||||
|  |     word-wrap: break-word; | ||||||
| 
 | 
 | ||||||
|     pre { |     pre { | ||||||
|       background: none !important; |       background: none !important; | ||||||
|  | @ -40,6 +41,15 @@ | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   .top_box_content { | ||||||
|  |     .box-title { | ||||||
|  |       color: $style_color; | ||||||
|  |       font-size: 18px; | ||||||
|  |       font-weight: normal; | ||||||
|  |       line-height: 28px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   .middle_box_content { |   .middle_box_content { | ||||||
|     @include border-radius(0); |     @include border-radius(0); | ||||||
|     border: none; |     border: none; | ||||||
|  | @ -64,7 +74,7 @@ | ||||||
| 
 | 
 | ||||||
|   border: 1px solid #eaeaea; |   border: 1px solid #eaeaea; | ||||||
|   @include border-radius(4px); |   @include border-radius(4px); | ||||||
|    | 
 | ||||||
|   border-color: #CCC; |   border-color: #CCC; | ||||||
|   @include solid-shade; |   @include solid-shade; | ||||||
| 
 | 
 | ||||||
|  | @ -83,6 +93,10 @@ | ||||||
|     border-top: 1px solid #eaeaea; |     border-top: 1px solid #eaeaea; | ||||||
|     border-bottom: 1px solid #bbb; |     border-bottom: 1px solid #bbb; | ||||||
| 
 | 
 | ||||||
|  |     > a { | ||||||
|  |       text-shadow: 0 1px 1px #fff; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     &.small { |     &.small { | ||||||
|       line-height: 28px; |       line-height: 28px; | ||||||
|       font-size: 14px; |       font-size: 14px; | ||||||
|  | @ -138,19 +152,6 @@ | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   li, .wll { |  | ||||||
|     padding: 10px; |  | ||||||
|     &:first-child { |  | ||||||
|       @include border-radius(4px 4px 0 0); |  | ||||||
|       border-top: none; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     &:last-child { |  | ||||||
|       @include border-radius(0 0 4px 4px); |  | ||||||
|       border: none; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   .ui-box-body { |   .ui-box-body { | ||||||
|     padding: 10px; |     padding: 10px; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -10,11 +10,6 @@ | ||||||
| /** COMMON CLASSES **/ | /** COMMON CLASSES **/ | ||||||
| .left { float:left } | .left { float:left } | ||||||
| .right { float:right!important } | .right { float:right!important } | ||||||
| .width-50p { width:50% } |  | ||||||
| .width-49p { width:49% } |  | ||||||
| .width-30p { width:30% } |  | ||||||
| .width-65p { width:65% } |  | ||||||
| .width-100p { width:100% } |  | ||||||
| .append-bottom-10 { margin-bottom:10px } | .append-bottom-10 { margin-bottom:10px } | ||||||
| .append-bottom-20 { margin-bottom:20px } | .append-bottom-20 { margin-bottom:20px } | ||||||
| .prepend-top-10 { margin-top:10px } | .prepend-top-10 { margin-top:10px } | ||||||
|  | @ -30,6 +25,7 @@ | ||||||
| .borders { border: 1px solid #ccc; @include shade; } | .borders { border: 1px solid #ccc; @include shade; } | ||||||
| .hint { font-style: italic; color: #999; } | .hint { font-style: italic; color: #999; } | ||||||
| .light { color: #888 } | .light { color: #888 } | ||||||
|  | .tiny { font-weight: normal } | ||||||
| 
 | 
 | ||||||
| /** PILLS & TABS**/ | /** PILLS & TABS**/ | ||||||
| .nav-pills a:hover { background-color: #888; } | .nav-pills a:hover { background-color: #888; } | ||||||
|  | @ -99,18 +95,21 @@ input[type='search'].search-text-input { | ||||||
|   border: 1px solid #ccc; |   border: 1px solid #ccc; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | input[type='text'].danger { | ||||||
|  |   background: #F2DEDE!important; | ||||||
|  |   border-color: #D66; | ||||||
|  |   text-shadow: 0 1px 1px #fff | ||||||
|  | } | ||||||
|  | 
 | ||||||
| fieldset legend { font-size: 17px; } | fieldset legend { font-size: 17px; } | ||||||
| 
 | 
 | ||||||
| ul.nav.nav-projects-tabs { | /** PAGINATION **/ | ||||||
|   @extend .nav-tabs; | .gitlab_pagination { | ||||||
| 
 |   span a { color: $link_color; } | ||||||
|   padding-left: 8px; |   .prev, .next, .current, .page a { | ||||||
| 
 |     padding: 10px; | ||||||
|   li { |   } | ||||||
|     a { |   .current { | ||||||
|       padding: 4px 20px; |     border-bottom: 2px solid $style_color; | ||||||
|       margin-top: 2px; |  | ||||||
|       border-color: #DDD; |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -43,11 +43,15 @@ | ||||||
|         padding: 0 4px; |         padding: 0 4px; | ||||||
|       } |       } | ||||||
|       padding: 20px; |       padding: 20px; | ||||||
|       h1, h2 { | 
 | ||||||
|         line-height: 46px; |       h1 { font-size: 26px; line-height: 46px; } | ||||||
|       } |       h2 { font-size: 22px; line-height: 42px; } | ||||||
|       h3, h4 { |       h3 { font-size: 20px; line-height: 40px; } | ||||||
|         line-height: 40px; |       h4 { font-size: 18px; line-height: 32px; } | ||||||
|  |       h5 { font-size: 16px; line-height: 26px; } | ||||||
|  | 
 | ||||||
|  |       .white .highlight pre { | ||||||
|  |         background: #f5f5f5; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,23 +1,38 @@ | ||||||
| /** LISTS **/ | /** | ||||||
| 
 |  * Well styled list | ||||||
| ul { |  * | ||||||
|   /** |  */ | ||||||
|    * List li block element #1 | .well-list { | ||||||
|    * |   margin: 0; | ||||||
|    */ |   list-style: none; | ||||||
|   .wll { |   li { | ||||||
|     background-color: #FFF; |     background-color: #FFF; | ||||||
|     padding: 10px 5px; |     padding: 10px; | ||||||
|     min-height: 20px; |     min-height: 20px; | ||||||
|     border-bottom: 1px solid #eee; |     border-bottom: 1px solid #eee; | ||||||
|     border-bottom: 1px solid rgba(0, 0, 0, 0.05); |     border-bottom: 1px solid rgba(0, 0, 0, 0.05); | ||||||
| 
 | 
 | ||||||
|  |     &.disabled { | ||||||
|  |       color: #888; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     &.smoke { background-color: #f5f5f5; } |     &.smoke { background-color: #f5f5f5; } | ||||||
|  | 
 | ||||||
|     &:hover { |     &:hover { | ||||||
|       background: $hover; |       background: $hover; | ||||||
|       border-bottom: 1px solid #ADF; |       border-bottom: 1px solid #ADF; | ||||||
|     } |     } | ||||||
|     &:last-child { border:none } | 
 | ||||||
|  |     &:first-child { | ||||||
|  |       @include border-radius(4px 4px 0 0); | ||||||
|  |       border-top: none; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     &:last-child { | ||||||
|  |       @include border-radius(0 0 4px 4px); | ||||||
|  |       border: none; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     .author { color: #999; } |     .author { color: #999; } | ||||||
| 
 | 
 | ||||||
|     p { |     p { | ||||||
|  | @ -29,6 +44,11 @@ ul { | ||||||
|         top: 3px; |         top: 3px; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     .well-title { | ||||||
|  |       font-size: 14px; | ||||||
|  |       line-height: 18px; | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -39,3 +59,17 @@ ol, ul { | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /** light list with border-bottom between li **/ | ||||||
|  | ul.bordered-list { | ||||||
|  |   margin: 5px 0px; | ||||||
|  |   padding: 0px; | ||||||
|  |   li { | ||||||
|  |     padding: 5px 0; | ||||||
|  |     border-bottom: 1px solid #EEE; | ||||||
|  |     overflow: hidden; | ||||||
|  |     display: block; | ||||||
|  |     margin: 0px; | ||||||
|  |     &:last-child { border:none } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -57,4 +57,13 @@ | ||||||
| 
 | 
 | ||||||
| @mixin solid-shade { | @mixin solid-shade { | ||||||
|   @include box-shadow(0 0 0 3px #f1f1f1); |   @include box-shadow(0 0 0 3px #f1f1f1); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | @mixin header-font { | ||||||
|  |   color: $style_color; | ||||||
|  |   text-shadow: 0 1px 1px #FFF; | ||||||
|  |   font-family: 'Korolev', sans-serif; | ||||||
|  |   font-size: 28px; | ||||||
|  |   line-height: 48px; | ||||||
|  |   font-weight: normal; | ||||||
|  | } | ||||||
|  | @ -2,4 +2,4 @@ | ||||||
| $primary_color: #2FA0BB; | $primary_color: #2FA0BB; | ||||||
| $link_color: #3A89A3; | $link_color: #3A89A3; | ||||||
| $style_color: #474D57; | $style_color: #474D57; | ||||||
| $hover: #D9EDF7; | $hover: #D9EDF7; | ||||||
|  | @ -1,7 +1,8 @@ | ||||||
| .black .highlight { | .black .highlight { | ||||||
|  |   background-color: #333; | ||||||
|   pre { |   pre { | ||||||
|     background-color: #333; |  | ||||||
|     color: #eee; |     color: #eee; | ||||||
|  |     background: inherit; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .hll { display: block; background-color: darken($hover, 65%) } |   .hll { display: block; background-color: darken($hover, 65%) } | ||||||
|  |  | ||||||
|  | @ -1,27 +1,3 @@ | ||||||
| /* |  | ||||||
|  * jQuery UI CSS Framework 1.8.7 |  | ||||||
|  * |  | ||||||
|  * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) |  | ||||||
|  * Dual licensed under the MIT or GPL Version 2 licenses. |  | ||||||
|  * http://jquery.org/license |  | ||||||
|  * |  | ||||||
|  * http://docs.jquery.com/UI/Theming/API |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| /* Layout helpers |  | ||||||
| ----------------------------------*/ |  | ||||||
| .ui-helper-hidden { display: none; } |  | ||||||
| .ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } |  | ||||||
| .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } |  | ||||||
| .ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } |  | ||||||
| .ui-helper-clearfix { display: inline-block; } |  | ||||||
| /* required comment for clearfix to work in Opera \*/ |  | ||||||
| * html .ui-helper-clearfix { height:1%; } |  | ||||||
| .ui-helper-clearfix { display:block; } |  | ||||||
| /* end clearfix */ |  | ||||||
| .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /* Interaction Cues | /* Interaction Cues | ||||||
| ----------------------------------*/ | ----------------------------------*/ | ||||||
| .ui-state-disabled { cursor: default !important; } | .ui-state-disabled { cursor: default !important; } | ||||||
|  | @ -140,26 +116,6 @@ | ||||||
| /* Overlays */ | /* Overlays */ | ||||||
| .ui-widget-overlay { background: #262b33; opacity: .70;filter:Alpha(Opacity=70); } | .ui-widget-overlay { background: #262b33; opacity: .70;filter:Alpha(Opacity=70); } | ||||||
| .ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #000000; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; } | .ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #000000; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; } | ||||||
| /* |  | ||||||
|  * jQuery UI Resizable 1.8.7 |  | ||||||
|  * |  | ||||||
|  * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) |  | ||||||
|  * Dual licensed under the MIT or GPL Version 2 licenses. |  | ||||||
|  * http://jquery.org/license |  | ||||||
|  * |  | ||||||
|  * http://docs.jquery.com/UI/Resizable#theming |  | ||||||
|  */ |  | ||||||
| .ui-resizable { position: relative;} |  | ||||||
| .ui-resizable-handle { position: absolute; font-size: 0.1px; z-index: 999; display: block;} |  | ||||||
| .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } |  | ||||||
| .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } |  | ||||||
| .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } |  | ||||||
| .ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } |  | ||||||
| .ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } |  | ||||||
| .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } |  | ||||||
| .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } |  | ||||||
| .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } |  | ||||||
| .ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;} |  | ||||||
| /* | /* | ||||||
|  * jQuery UI Selectable 1.8.7 |  * jQuery UI Selectable 1.8.7 | ||||||
|  * |  * | ||||||
|  | @ -240,34 +196,7 @@ | ||||||
|   cursor: pointer; |   cursor: pointer; | ||||||
|   font-weight: bold; |   font-weight: bold; | ||||||
| } | } | ||||||
| /* |  | ||||||
|  * jQuery UI Slider 1.8.7 |  | ||||||
|  * |  | ||||||
|  * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) |  | ||||||
|  * Dual licensed under the MIT or GPL Version 2 licenses. |  | ||||||
|  * http://jquery.org/license |  | ||||||
|  * |  | ||||||
|  * http://docs.jquery.com/UI/Slider#theming |  | ||||||
|  */ |  | ||||||
| .ui-slider { position: relative; text-align: left; background: #d7d7d7; z-index: 1; } |  | ||||||
| .ui-slider { -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.5) inset; -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.5) inset; box-shadow: 0 1px 2px rgba(0,0,0,0.5) inset; } |  | ||||||
| .ui-slider .ui-slider-handle { background: url(slider_handles.png) 0px -23px no-repeat; position: absolute; z-index: 2; width: 23px; height: 23px; cursor: default; border: none; outline: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } |  | ||||||
| .ui-slider  .ui-state-hover, .ui-slider  .ui-state-active { background-position: 0 0; } |  | ||||||
| .ui-slider .ui-slider-range { background: #a3cae0; position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } |  | ||||||
| .ui-slider .ui-slider-range { -moz-box-shadow: 0 1px 2px rgba(17,35,45,0.6) inset; -webkit-box-shadow: 0 1px 2px rgba(17,35,45,0.6) inset; box-shadow: 0 1px 2px rgba(17,35,45,0.6) inset; } |  | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| .ui-slider-horizontal { height: 5px; } |  | ||||||
| .ui-slider-horizontal .ui-slider-handle { top: -8px; margin-left: -13px; } |  | ||||||
| .ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } |  | ||||||
| .ui-slider-horizontal .ui-slider-range-min { left: 0; } |  | ||||||
| .ui-slider-horizontal .ui-slider-range-max { right: 0; } |  | ||||||
| 
 |  | ||||||
| .ui-slider-vertical { width: 5px; height: 100px; } |  | ||||||
| .ui-slider-vertical .ui-slider-handle { left: -8px; margin-left: 0; margin-bottom: -13px; } |  | ||||||
| .ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } |  | ||||||
| .ui-slider-vertical .ui-slider-range-min { bottom: 0; } |  | ||||||
| .ui-slider-vertical .ui-slider-range-max { top: 0; } |  | ||||||
| /* | /* | ||||||
|  * jQuery UI Datepicker 1.8.7 |  * jQuery UI Datepicker 1.8.7 | ||||||
|  * |  * | ||||||
|  | @ -326,45 +255,3 @@ | ||||||
| .ui-datepicker table .ui-state-highlight { border-color: #ADE; } | .ui-datepicker table .ui-state-highlight { border-color: #ADE; } | ||||||
| .ui-datepicker-calendar .ui-state-default { background: transparent; border-color: #FFF; } | .ui-datepicker-calendar .ui-state-default { background: transparent; border-color: #FFF; } | ||||||
| .ui-datepicker-calendar .ui-state-active { background: #D9EDF7; border-color: #ADE; color: #3A89A3; font-weight: bold; text-shadow: 0 1px 1px #fff; } | .ui-datepicker-calendar .ui-state-active { background: #D9EDF7; border-color: #ADE; color: #3A89A3; font-weight: bold; text-shadow: 0 1px 1px #fff; } | ||||||
| 
 |  | ||||||
| /* with multiple calendars */ |  | ||||||
| .ui-datepicker.ui-datepicker-multi { width:auto; } |  | ||||||
| .ui-datepicker-multi .ui-datepicker-group { float:left; } |  | ||||||
| .ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } |  | ||||||
| .ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } |  | ||||||
| .ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } |  | ||||||
| .ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } |  | ||||||
| .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } |  | ||||||
| .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } |  | ||||||
| .ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } |  | ||||||
| .ui-datepicker-row-break { clear:both; width:100%; } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /* Extra Input Field Styling */ |  | ||||||
| .ui-form textarea, .ui-form input:not([type="submit"]):not([type="button"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]) { |  | ||||||
| 	padding: 3px; |  | ||||||
| 	-webkit-border-radius: 2px; |  | ||||||
| 	-moz-border-radius: 2px; |  | ||||||
| 	border-radius: 2px; |  | ||||||
| 	border: 1px solid #cecece; |  | ||||||
| 	outline: none; |  | ||||||
| 	-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.1) inset, 0 1px 0 rgba(255,255,255,0.2); |  | ||||||
| 	-moz-box-shadow: 0 1px 3px rgba(0,0,0,0.1) inset, 0 1px 0 rgba(255,255,255,0.2); |  | ||||||
| 	box-shadow: 0 1px 3px rgba(0,0,0,0.1) inset, 0 1px 0 rgba(255,255,255,0.2); |  | ||||||
|     -webkit-transition: all 250ms ease-in-out; |  | ||||||
|     -moz-transition: all 250ms ease-in-out; |  | ||||||
|     -o-transition: all 250ms ease-in-out; |  | ||||||
|     transition: all 250ms ease-in-out; |  | ||||||
| } |  | ||||||
| .ui-form textarea:hover, .ui-form input:not([type="submit"]):not([type="button"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]):hover { |  | ||||||
| 	border: 1px solid #bdbdbd; |  | ||||||
| 	-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.2) inset, 0 1px 0 rgba(255,255,255,0.2); |  | ||||||
| 	-moz-box-shadow: 0 1px 3px rgba(0,0,0,0.2) inset, 0 1px 0 rgba(255,255,255,0.2); |  | ||||||
| 	box-shadow: 0 1px 3px rgba(0,0,0,0.2) inset, 0 1px 0 rgba(255,255,255,0.2); |  | ||||||
| } |  | ||||||
| .ui-form textarea:focus, .ui-form input:not([type="submit"]):not([type="button"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]):focus { |  | ||||||
| 	border: 1px solid #95bdd4; |  | ||||||
| 	-webkit-box-shadow: 0 2px 3px rgba(161,202,226,0.5) inset, 0 1px 0 rgba(255,255,255,0.2); |  | ||||||
| 	-moz-box-shadow: 0 2px 3px rgba(161,202,226,0.5) inset, 0 1px 0 rgba(255,255,255,0.2); |  | ||||||
| 	box-shadow: 0 2px 3px rgba(161,202,226,0.5) inset, 0 1px 0 rgba(255,255,255,0.2); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -1,144 +0,0 @@ | ||||||
| /** Override bootstrap variables **/ |  | ||||||
| $baseFontSize: 13px !default; |  | ||||||
| $baseLineHeight: 18px !default; |  | ||||||
| 
 |  | ||||||
| // BOOTSTRAP |  | ||||||
| @import "bootstrap"; |  | ||||||
| @import "bootstrap/responsive-utilities"; |  | ||||||
| @import "bootstrap/responsive-1200px-min"; |  | ||||||
| 
 |  | ||||||
| // FONT AWESOME |  | ||||||
| @import "font-awesome"; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Variables |  | ||||||
|  * Contains colors |  | ||||||
|  */ |  | ||||||
| @import "variables.scss"; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Custom fonts |  | ||||||
|  * Contains @font-face font Korolev and default $monotype |  | ||||||
|  */ |  | ||||||
| @import "fonts.scss"; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * General mixins. |  | ||||||
|  * Contains rounded borders, gradients and shades |  | ||||||
|  */ |  | ||||||
| @import "mixins.scss"; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Header of application. |  | ||||||
|  * Contain application logo, search panel, profile icon |  | ||||||
|  */ |  | ||||||
| @import "sections/header.scss"; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Navigation menu of application. |  | ||||||
|  * Panel with links to pages depends on project, profile or admin area |  | ||||||
|  */ |  | ||||||
| @import "sections/nav.scss"; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * This file represent some UI that can be changed |  | ||||||
|  * during web app restyle or theme select. |  | ||||||
|  * |  | ||||||
|  * Next items should be placed there |  | ||||||
|  * - link, button colors |  | ||||||
|  * - header restyles |  | ||||||
|  * - main menu restyles |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| @import "themes/ui_basic.scss"; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * UI themes: |  | ||||||
|  */ |  | ||||||
| @import "themes/ui_mars.scss"; |  | ||||||
| @import "themes/ui_modern.scss"; |  | ||||||
| @import "themes/ui_gray.scss"; |  | ||||||
| @import "themes/ui_color.scss"; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * GitLab bootstrap. |  | ||||||
|  * Overrides some styles of twitter bootstrap. |  | ||||||
|  * Also give some common classes for GitLab app |  | ||||||
|  */ |  | ||||||
| @import "gitlab_bootstrap/common.scss"; |  | ||||||
| @import "gitlab_bootstrap/typography.scss"; |  | ||||||
| @import "gitlab_bootstrap/buttons.scss"; |  | ||||||
| @import "gitlab_bootstrap/blocks.scss"; |  | ||||||
| @import "gitlab_bootstrap/files.scss"; |  | ||||||
| @import "gitlab_bootstrap/tables.scss"; |  | ||||||
| @import "gitlab_bootstrap/lists.scss"; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Most of application styles placed here. |  | ||||||
|  * This file represent common UI that should not be changed between themes |  | ||||||
|  * or project restyling like form width or user avatar class or commit title |  | ||||||
|  * |  | ||||||
|  * TODO: clean it |  | ||||||
|  */ |  | ||||||
| @import "common.scss"; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Styles necessary to support JS behaviours. |  | ||||||
|  */ |  | ||||||
| @import "behaviors.scss"; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Styles related to specific part of app |  | ||||||
|  */ |  | ||||||
| @import "sections/commits.scss"; |  | ||||||
| @import "sections/issues.scss"; |  | ||||||
| @import "sections/projects.scss"; |  | ||||||
| @import "sections/merge_requests.scss"; |  | ||||||
| @import "sections/graph.scss"; |  | ||||||
| @import "sections/events.scss"; |  | ||||||
| @import "sections/themes.scss"; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * This scss file redefine chozen selectbox styles for |  | ||||||
|  * project Branch/Tag select element |  | ||||||
|  */ |  | ||||||
| @import "ref_select.scss"; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Code (files list) styles. Browsing project files there |  | ||||||
|  */ |  | ||||||
| @import "sections/tree.scss"; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * This file represent notes(comments) styles |  | ||||||
|  */ |  | ||||||
| @import "sections/notes.scss"; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * This file represent profile styles |  | ||||||
|  */ |  | ||||||
| @import "sections/profile.scss"; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Devise styles |  | ||||||
|  */ |  | ||||||
| @import "sections/login.scss"; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * CODE HIGHTLIGHT BASE |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| @import "highlight/white.scss"; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * CODE HIGHTLIGHT DARK schema |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| @import "highlight/dark.scss"; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * File Editor styles |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| @import "sections/editor.scss"; |  | ||||||
|  | @ -232,8 +232,6 @@ | ||||||
| 
 | 
 | ||||||
| /** COMMIT ROW **/ | /** COMMIT ROW **/ | ||||||
| .commit { | .commit { | ||||||
|   @extend .wll; |  | ||||||
| 
 |  | ||||||
|   .browse_code_link_holder { |   .browse_code_link_holder { | ||||||
|     @extend .span2; |     @extend .span2; | ||||||
|     float: right; |     float: right; | ||||||
|  | @ -305,3 +303,17 @@ | ||||||
|   color: #fff; |   color: #fff; | ||||||
|   font-family: $monospace; |   font-family: $monospace; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | .commits-compare-switch{ | ||||||
|  |   background: url("switch_icon.png") no-repeat center center; | ||||||
|  |   width: 16px; | ||||||
|  |   height: 18px; | ||||||
|  |   text-indent: -9999px; | ||||||
|  |   float: left; | ||||||
|  |   margin-right: 9px; | ||||||
|  |   border: 1px solid #DDD; | ||||||
|  |   @include border-radius(4px); | ||||||
|  |   padding: 4px; | ||||||
|  |   background-color: #EEE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -31,7 +31,6 @@ | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| .event-item { | .event-item { | ||||||
|   min-height: 40px; |  | ||||||
|   border-bottom: 1px solid #eee; |   border-bottom: 1px solid #eee; | ||||||
|   .event-title { |   .event-title { | ||||||
|     color: #333; |     color: #333; | ||||||
|  | @ -50,14 +49,18 @@ | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   .avatar { |   .avatar { | ||||||
|     width: 32px; |     position: relative; | ||||||
|  |     top: -3px; | ||||||
|   } |   } | ||||||
|   .event_icon { |   .event_icon { | ||||||
|  |     position: relative; | ||||||
|     float: right; |     float: right; | ||||||
|     border: 1px solid #EEE; |     border: 1px solid #EEE; | ||||||
|     padding: 5px; |     padding: 5px; | ||||||
|     @include border-radius(5px); |     @include border-radius(5px); | ||||||
|     background: #F9F9F9; |     background: #F9F9F9; | ||||||
|  |     margin-left: 10px; | ||||||
|  |     top: -6px; | ||||||
|     img { |     img { | ||||||
|       width: 20px; |       width: 20px; | ||||||
|     } |     } | ||||||
|  | @ -71,9 +74,8 @@ | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   padding: 15px 5px; |   padding: 16px 5px; | ||||||
|   &:last-child { border:none } |   &:last-child { border:none } | ||||||
|   .wll:hover { background:none } |  | ||||||
| 
 | 
 | ||||||
|   .event_commits { |   .event_commits { | ||||||
|     margin-top: 5px; |     margin-top: 5px; | ||||||
|  |  | ||||||
|  | @ -44,14 +44,9 @@ header { | ||||||
|         background: url('logo_dark.png') no-repeat 0px 2px; |         background: url('logo_dark.png') no-repeat 0px 2px; | ||||||
|         float: left; |         float: left; | ||||||
|         margin-left: 2px; |         margin-left: 2px; | ||||||
|         font-size: 30px; |  | ||||||
|         line-height: 48px; |  | ||||||
|         font-weight: normal; |  | ||||||
|         color: $style_color; |  | ||||||
|         text-shadow: 0 1px 1px #FFF; |  | ||||||
|         padding-left: 45px; |         padding-left: 45px; | ||||||
|         height: 40px; |         height: 40px; | ||||||
|         font-family: 'Korolev', sans-serif; |         @include header-font; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | @ -66,12 +61,7 @@ header { | ||||||
|     float: left; |     float: left; | ||||||
|     margin: 0; |     margin: 0; | ||||||
|     margin-right: 30px; |     margin-right: 30px; | ||||||
|     font-size: 30px; |     @include header-font; | ||||||
|     line-height: 48px; |  | ||||||
|     font-weight: normal; |  | ||||||
|     color: $style_color; |  | ||||||
|     text-shadow: 0 1px 1px #FFF; |  | ||||||
|     font-family: 'Korolev', sans-serif; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|  | @ -172,7 +162,7 @@ header { | ||||||
|     display: none; |     display: none; | ||||||
|     z-index: 100000; |     z-index: 100000; | ||||||
|     @include border-radius(4px); |     @include border-radius(4px); | ||||||
|     width: 100px; |     width: 130px; | ||||||
|     position: absolute; |     position: absolute; | ||||||
|     right: 5px; |     right: 5px; | ||||||
|     top: 38px; |     top: 38px; | ||||||
|  | @ -181,7 +171,7 @@ header { | ||||||
|     box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); |     box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); | ||||||
|     a { |     a { | ||||||
|       color: #fff; |       color: #fff; | ||||||
|       padding: 7px 10px; |       padding: 12px 15px; | ||||||
|       display: block; |       display: block; | ||||||
|       text-shadow: none; |       text-shadow: none; | ||||||
|       border-bottom: 1px solid #666; |       border-bottom: 1px solid #666; | ||||||
|  | @ -204,8 +194,8 @@ header { | ||||||
|     } |     } | ||||||
|     &:last-child { |     &:last-child { | ||||||
|       @include border-radius(0 0 5px 5px); |       @include border-radius(0 0 5px 5px); | ||||||
|       border-bottom: 0;  |       border-bottom: 0; | ||||||
|     }  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -121,12 +121,3 @@ input.check_all_issues { | ||||||
| #update_status { | #update_status { | ||||||
|   width: 100px; |   width: 100px; | ||||||
| } | } | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Milestones list |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| .milestone { |  | ||||||
|   @extend .wll; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -136,9 +136,3 @@ li.merge_request { | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| .status-badge { |  | ||||||
|   height: 32px; |  | ||||||
|   width: 100%; |  | ||||||
|   @include border-radius(5px); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -3,15 +3,13 @@ | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| ul.main_menu { | ul.main_menu { | ||||||
|   @include border-radius(4px); |  | ||||||
|   margin: auto; |   margin: auto; | ||||||
|   margin: 30px 0; |   margin: 30px 0; | ||||||
|   border: 1px solid #BBB; |   margin-top: 10px; | ||||||
|  |   border-bottom: 1px solid #DDD; | ||||||
|   height: 37px; |   height: 37px; | ||||||
|   @include bg-gray-gradient; |  | ||||||
|   position: relative; |   position: relative; | ||||||
|   overflow: hidden; |   overflow: hidden; | ||||||
|   @include shade; |  | ||||||
|   .count { |   .count { | ||||||
|     position: relative; |     position: relative; | ||||||
|     top: -1px; |     top: -1px; | ||||||
|  | @ -24,9 +22,6 @@ ul.main_menu { | ||||||
|     line-height: 14px; |     line-height: 14px; | ||||||
|     text-align: center; |     text-align: center; | ||||||
|     color: #777; |     color: #777; | ||||||
|     background: #f2f2f2; |  | ||||||
|     border-top: 1px solid #CCC; |  | ||||||
|     @include border-radius(8px); |  | ||||||
|   } |   } | ||||||
|   .label { |   .label { | ||||||
|     background: $hover; |     background: $hover; | ||||||
|  | @ -38,23 +33,10 @@ ul.main_menu { | ||||||
|     margin: 0; |     margin: 0; | ||||||
|     display: table-cell; |     display: table-cell; | ||||||
|     width: 1%; |     width: 1%; | ||||||
|     border-right: 1px solid #DDD; |  | ||||||
|     border-left: 1px solid #EEE; |  | ||||||
|     border-bottom: 2px solid #CFCFCF; |  | ||||||
| 
 |  | ||||||
|     &:first-child{ |  | ||||||
|       @include border-radius(5px 0 0 5px); |  | ||||||
|       border-left: 0; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     &.active { |     &.active { | ||||||
|       background-color: #D5D5D5; |       border-bottom: 2px solid #474D57; | ||||||
|       border-right: 1px solid #BBB; |       a { | ||||||
|       border-left: 1px solid #BBB; |         color: $style_color; | ||||||
|       @include border-radius(0 0 1px 1px); |  | ||||||
|       &:first-child{ |  | ||||||
|         border-bottom: none; |  | ||||||
|         border-left: none; |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -73,10 +55,10 @@ ul.main_menu { | ||||||
|   a { |   a { | ||||||
|     display: block; |     display: block; | ||||||
|     text-align: center; |     text-align: center; | ||||||
|     font-weight: bold; |     font-weight: normal; | ||||||
|     height: 35px; |     height: 35px; | ||||||
|     line-height: 36px; |     line-height: 36px; | ||||||
|     color: $style_color; |     color: #777; | ||||||
|     text-shadow: 0 1px 1px white; |     text-shadow: 0 1px 1px white; | ||||||
|     padding: 0 10px; |     padding: 0 10px; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -4,12 +4,11 @@ | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   .side { |   .side { | ||||||
|     @extend .span4; |  | ||||||
|     @extend .right; |     @extend .right; | ||||||
| 
 | 
 | ||||||
|     .groups_box, |     .groups_box, | ||||||
|     .projects_box { |     .projects_box { | ||||||
|       h5 { |       > h5 { | ||||||
|         color: $style_color; |         color: $style_color; | ||||||
|         font-size: 16px; |         font-size: 16px; | ||||||
|         text-shadow: 0 1px 1px #fff; |         text-shadow: 0 1px 1px #fff; | ||||||
|  | @ -17,37 +16,22 @@ | ||||||
|         line-height: 32px; |         line-height: 32px; | ||||||
|         font-size: 14px; |         font-size: 14px; | ||||||
|       } |       } | ||||||
|       ul { |       .nav-projects-tabs li { padding: 0; } | ||||||
|         li { |       .well-list { | ||||||
|           padding: 0; |         .arrow { | ||||||
|           a { |           float: right; | ||||||
|             display: block; |           padding: 10px; | ||||||
|             .group_name { |           margin: 0; | ||||||
|               font-size: 14px; |         } | ||||||
|               line-height: 18px; |         .last_activity { | ||||||
|             } |           padding-top: 5px; | ||||||
|             .project_name { |           display: block; | ||||||
|               color: #4fa2bd; |           span, strong { | ||||||
|               font-size: 14px; |             font-size: 12px; | ||||||
|               line-height: 18px; |             color: #666; | ||||||
|             } |  | ||||||
|             .arrow { |  | ||||||
|               float: right; |  | ||||||
|               padding: 10px; |  | ||||||
|               margin: 0; |  | ||||||
|             } |  | ||||||
|             .last_activity { |  | ||||||
|               padding-top: 5px; |  | ||||||
|               display: block; |  | ||||||
|               span, strong { |  | ||||||
|                 font-size: 12px; |  | ||||||
|                 color: #666; |  | ||||||
|               } |  | ||||||
|             } |  | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       @extend .leftbar; |  | ||||||
|       @extend .ui-box; |       @extend .ui-box; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | @ -117,3 +101,25 @@ | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | ul.nav.nav-projects-tabs { | ||||||
|  |   @extend .nav-tabs; | ||||||
|  | 
 | ||||||
|  |   padding-left: 8px; | ||||||
|  | 
 | ||||||
|  |   li { | ||||||
|  |     a { | ||||||
|  |       padding: 4px 20px; | ||||||
|  |       margin-top: 2px; | ||||||
|  |       border-color: #DDD; | ||||||
|  |       background-color: #EEE; | ||||||
|  |       text-shadow: 0 1px 1px white; | ||||||
|  |       color: #555; | ||||||
|  |     } | ||||||
|  |     &.active { | ||||||
|  |       a { | ||||||
|  |         font-weight: bold; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,9 @@ | ||||||
|  | .snippet.file_holder { | ||||||
|  |   .file_title { | ||||||
|  |     .snippet-file-name { | ||||||
|  |       position: relative; | ||||||
|  |       top: -4px; | ||||||
|  |       left: -4px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,43 @@ | ||||||
|  | .votes { | ||||||
|  |   font-size: 13px; | ||||||
|  |   line-height: 15px; | ||||||
|  |   .progress { | ||||||
|  |     height: 4px; | ||||||
|  |     margin: 0; | ||||||
|  |     .bar { | ||||||
|  |       float: left; | ||||||
|  |       height: 100%; | ||||||
|  |     } | ||||||
|  |     .bar-success { | ||||||
|  |       @include linear-gradient(#62C462, #51A351); | ||||||
|  |       background-color: #468847; | ||||||
|  |     } | ||||||
|  |     .bar-danger { | ||||||
|  |       @include linear-gradient(#EE5F5B, #BD362F); | ||||||
|  |       background-color: #B94A48; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   .upvotes { | ||||||
|  |     display: inline-block; | ||||||
|  |     color: #468847; | ||||||
|  |   } | ||||||
|  |   .downvotes { | ||||||
|  |     display: inline-block; | ||||||
|  |     color: #B94A48; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | .votes-block { | ||||||
|  |   margin: 14px 6px 6px 0; | ||||||
|  |   .downvotes { | ||||||
|  |     float: right; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | .votes-inline { | ||||||
|  |   display: inline-block; | ||||||
|  |   margin: 0 8px; | ||||||
|  |   .progress { | ||||||
|  |     display: inline-block; | ||||||
|  |     padding: 0 0 2px; | ||||||
|  |     width: 45px; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -4,18 +4,6 @@ | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| .ui_basic { | .ui_basic { | ||||||
|   /* |  | ||||||
|    * Common styles |  | ||||||
|    * |  | ||||||
|    */ |  | ||||||
|   a { |  | ||||||
|     color: $link_color; |  | ||||||
|     &:hover { |  | ||||||
|       text-decoration: none; |  | ||||||
|       color: $primary_color; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   .app_logo { |   .app_logo { | ||||||
|     .separator { |     .separator { | ||||||
|       margin-left: 0; |       margin-left: 0; | ||||||
|  |  | ||||||
|  | @ -2,7 +2,9 @@ class ProjectUpdateContext < BaseContext | ||||||
|   def execute(role = :default) |   def execute(role = :default) | ||||||
|     namespace_id = params[:project].delete(:namespace_id) |     namespace_id = params[:project].delete(:namespace_id) | ||||||
| 
 | 
 | ||||||
|     if namespace_id.present? |     allowed_transfer = can?(current_user, :change_namespace, project) || role == :admin | ||||||
|  | 
 | ||||||
|  |     if allowed_transfer && namespace_id.present? | ||||||
|       if namespace_id == Namespace.global_id |       if namespace_id == Namespace.global_id | ||||||
|         if project.namespace.present? |         if project.namespace.present? | ||||||
|           # Transfer to global namespace from anyone |           # Transfer to global namespace from anyone | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ class Admin::GroupsController < AdminController | ||||||
|   before_filter :group, only: [:edit, :show, :update, :destroy, :project_update] |   before_filter :group, only: [:edit, :show, :update, :destroy, :project_update] | ||||||
| 
 | 
 | ||||||
|   def index |   def index | ||||||
|     @groups = Group.scoped |     @groups = Group.order('name ASC') | ||||||
|     @groups = @groups.search(params[:name]) if params[:name].present? |     @groups = @groups.search(params[:name]) if params[:name].present? | ||||||
|     @groups = @groups.page(params[:page]).per(20) |     @groups = @groups.page(params[:page]).per(20) | ||||||
|   end |   end | ||||||
|  | @ -11,6 +11,7 @@ class Admin::GroupsController < AdminController | ||||||
|     @projects = Project.scoped |     @projects = Project.scoped | ||||||
|     @projects = @projects.not_in_group(@group) if @group.projects.present? |     @projects = @projects.not_in_group(@group) if @group.projects.present? | ||||||
|     @projects = @projects.all |     @projects = @projects.all | ||||||
|  |     @projects.reject!(&:empty_repo?) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def new |   def new | ||||||
|  |  | ||||||
|  | @ -4,12 +4,13 @@ class Admin::ProjectsController < AdminController | ||||||
|   def index |   def index | ||||||
|     @projects = Project.scoped |     @projects = Project.scoped | ||||||
|     @projects = @projects.where(namespace_id: params[:namespace_id]) if params[:namespace_id].present? |     @projects = @projects.where(namespace_id: params[:namespace_id]) if params[:namespace_id].present? | ||||||
|  |     @projects = @projects.where(namespace_id: nil) if params[:namespace_id] == Namespace.global_id | ||||||
|     @projects = @projects.search(params[:name]) if params[:name].present? |     @projects = @projects.search(params[:name]) if params[:name].present? | ||||||
|     @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20) |     @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def show |   def show | ||||||
|     @users = User.scoped |     @users = User.active | ||||||
|     @users = @users.not_in_project(@project) if @project.users.present? |     @users = @users.not_in_project(@project) if @project.users.present? | ||||||
|     @users = @users.all |     @users = @users.all | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ class Admin::UsersController < AdminController | ||||||
|     @admin_users = User.scoped |     @admin_users = User.scoped | ||||||
|     @admin_users = @admin_users.filter(params[:filter]) |     @admin_users = @admin_users.filter(params[:filter]) | ||||||
|     @admin_users = @admin_users.search(params[:name]) if params[:name].present? |     @admin_users = @admin_users.search(params[:name]) if params[:name].present? | ||||||
|     @admin_users = @admin_users.order("updated_at DESC").page(params[:page]) |     @admin_users = @admin_users.order("name ASC").page(params[:page]) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def show |   def show | ||||||
|  | @ -30,7 +30,7 @@ class Admin::UsersController < AdminController | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|   def new |   def new | ||||||
|     @admin_user = User.new({ projects_limit: Gitlab.config.default_projects_limit }, as: :admin) |     @admin_user = User.new({ projects_limit: Gitlab.config.gitlab.default_projects_limit }, as: :admin) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def edit |   def edit | ||||||
|  |  | ||||||
|  | @ -112,6 +112,10 @@ class ApplicationController < ActionController::Base | ||||||
|     render file: Rails.root.join("public", "404"), layout: false, status: "404" |     render file: Rails.root.join("public", "404"), layout: false, status: "404" | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   def render_403 | ||||||
|  |     render file: Rails.root.join("public", "403"), layout: false, status: "403" | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   def require_non_empty_project |   def require_non_empty_project | ||||||
|     redirect_to @project if @project.empty_repo? |     redirect_to @project if @project.empty_repo? | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  | @ -7,6 +7,8 @@ class DashboardController < ApplicationController | ||||||
|   def index |   def index | ||||||
|     @groups = current_user.authorized_groups |     @groups = current_user.authorized_groups | ||||||
| 
 | 
 | ||||||
|  |     @has_authorized_projects = @projects.count > 0 | ||||||
|  | 
 | ||||||
|     @projects = case params[:scope] |     @projects = case params[:scope] | ||||||
|                 when 'personal' then |                 when 'personal' then | ||||||
|                   @projects.personal(current_user) |                   @projects.personal(current_user) | ||||||
|  |  | ||||||
|  | @ -21,7 +21,7 @@ class GroupsController < ApplicationController | ||||||
| 
 | 
 | ||||||
|   # Get authored or assigned open merge requests |   # Get authored or assigned open merge requests | ||||||
|   def merge_requests |   def merge_requests | ||||||
|     @merge_requests = current_user.cared_merge_requests |     @merge_requests = current_user.cared_merge_requests.opened | ||||||
|     @merge_requests = @merge_requests.of_group(@group).recent.page(params[:page]).per(20) |     @merge_requests = @merge_requests.of_group(@group).recent.page(params[:page]).per(20) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  | @ -49,6 +49,7 @@ class GroupsController < ApplicationController | ||||||
|   def people |   def people | ||||||
|     @project = group.projects.find(params[:project_id]) if params[:project_id] |     @project = group.projects.find(params[:project_id]) if params[:project_id] | ||||||
|     @users = @project ? @project.users : group.users |     @users = @project ? @project.users : group.users | ||||||
|  |     @users.sort_by!(&:name) | ||||||
| 
 | 
 | ||||||
|     if @project |     if @project | ||||||
|       @team_member = @project.users_projects.new |       @team_member = @project.users_projects.new | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| class IssuesController < ProjectResourceController | class IssuesController < ProjectResourceController | ||||||
|   before_filter :module_enabled |   before_filter :module_enabled | ||||||
|   before_filter :issue, only: [:edit, :update, :destroy, :show] |   before_filter :issue, only: [:edit, :update, :show] | ||||||
| 
 | 
 | ||||||
|   # Allow read any issue |   # Allow read any issue | ||||||
|   before_filter :authorize_read_issue! |   before_filter :authorize_read_issue! | ||||||
|  | @ -11,9 +11,6 @@ class IssuesController < ProjectResourceController | ||||||
|   # Allow modify issue |   # Allow modify issue | ||||||
|   before_filter :authorize_modify_issue!, only: [:edit, :update] |   before_filter :authorize_modify_issue!, only: [:edit, :update] | ||||||
| 
 | 
 | ||||||
|   # Allow destroy issue |  | ||||||
|   before_filter :authorize_admin_issue!, only: [:destroy] |  | ||||||
| 
 |  | ||||||
|   respond_to :js, :html |   respond_to :js, :html | ||||||
| 
 | 
 | ||||||
|   def index |   def index | ||||||
|  | @ -79,15 +76,6 @@ class IssuesController < ProjectResourceController | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def destroy |  | ||||||
|     @issue.destroy |  | ||||||
| 
 |  | ||||||
|     respond_to do |format| |  | ||||||
|       format.html { redirect_to project_issues_path } |  | ||||||
|       format.js { render nothing: true } |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def sort |   def sort | ||||||
|     return render_404 unless can?(current_user, :admin_issue, @project) |     return render_404 unless can?(current_user, :admin_issue, @project) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| class MergeRequestsController < ProjectResourceController | class MergeRequestsController < ProjectResourceController | ||||||
|   before_filter :module_enabled |   before_filter :module_enabled | ||||||
|   before_filter :merge_request, only: [:edit, :update, :destroy, :show, :commits, :diffs, :automerge, :automerge_check] |   before_filter :merge_request, only: [:edit, :update, :show, :commits, :diffs, :automerge, :automerge_check, :ci_status] | ||||||
|   before_filter :validates_merge_request, only: [:show, :diffs] |   before_filter :validates_merge_request, only: [:show, :diffs] | ||||||
|   before_filter :define_show_vars, only: [:show, :diffs] |   before_filter :define_show_vars, only: [:show, :diffs] | ||||||
| 
 | 
 | ||||||
|  | @ -13,9 +13,6 @@ class MergeRequestsController < ProjectResourceController | ||||||
|   # Allow modify merge_request |   # Allow modify merge_request | ||||||
|   before_filter :authorize_modify_merge_request!, only: [:close, :edit, :update, :sort] |   before_filter :authorize_modify_merge_request!, only: [:close, :edit, :update, :sort] | ||||||
| 
 | 
 | ||||||
|   # Allow destroy merge_request |  | ||||||
|   before_filter :authorize_admin_merge_request!, only: [:destroy] |  | ||||||
| 
 |  | ||||||
|   def index |   def index | ||||||
|     @merge_requests = MergeRequestsLoadContext.new(project, current_user, params).execute |     @merge_requests = MergeRequestsLoadContext.new(project, current_user, params).execute | ||||||
|   end |   end | ||||||
|  | @ -90,14 +87,6 @@ class MergeRequestsController < ProjectResourceController | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def destroy |  | ||||||
|     @merge_request.destroy |  | ||||||
| 
 |  | ||||||
|     respond_to do |format| |  | ||||||
|       format.html { redirect_to project_merge_requests_url(@project) } |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def branch_from |   def branch_from | ||||||
|     @commit = project.commit(params[:ref]) |     @commit = project.commit(params[:ref]) | ||||||
|     @commit = CommitDecorator.decorate(@commit) |     @commit = CommitDecorator.decorate(@commit) | ||||||
|  | @ -108,6 +97,13 @@ class MergeRequestsController < ProjectResourceController | ||||||
|     @commit = CommitDecorator.decorate(@commit) |     @commit = CommitDecorator.decorate(@commit) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   def ci_status | ||||||
|  |     status = project.gitlab_ci_service.commit_status(merge_request.last_commit.sha) | ||||||
|  |     response = { status: status } | ||||||
|  | 
 | ||||||
|  |     render json: response | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   protected |   protected | ||||||
| 
 | 
 | ||||||
|   def merge_request |   def merge_request | ||||||
|  |  | ||||||
|  | @ -12,11 +12,12 @@ class MilestonesController < ProjectResourceController | ||||||
| 
 | 
 | ||||||
|   def index |   def index | ||||||
|     @milestones = case params[:f] |     @milestones = case params[:f] | ||||||
|                   when 'all'; @project.milestones |                   when 'all'; @project.milestones.order("closed, due_date DESC") | ||||||
|                   else @project.milestones.active |                   when 'closed'; @project.milestones.closed.order("due_date DESC") | ||||||
|  |                   else @project.milestones.active.order("due_date ASC") | ||||||
|                   end |                   end | ||||||
| 
 | 
 | ||||||
|     @milestones = @milestones.includes(:project).order("due_date") |     @milestones = @milestones.includes(:project) | ||||||
|     @milestones = @milestones.page(params[:page]).per(20) |     @milestones = @milestones.page(params[:page]).per(20) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  | @ -42,6 +43,7 @@ class MilestonesController < ProjectResourceController | ||||||
| 
 | 
 | ||||||
|   def create |   def create | ||||||
|     @milestone = @project.milestones.new(params[:milestone]) |     @milestone = @project.milestones.new(params[:milestone]) | ||||||
|  |     @milestone.author_id_of_changes = current_user.id | ||||||
| 
 | 
 | ||||||
|     if @milestone.save |     if @milestone.save | ||||||
|       redirect_to project_milestone_path(@project, @milestone) |       redirect_to project_milestone_path(@project, @milestone) | ||||||
|  | @ -51,7 +53,7 @@ class MilestonesController < ProjectResourceController | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def update |   def update | ||||||
|     @milestone.update_attributes(params[:milestone]) |     @milestone.update_attributes(params[:milestone].merge(author_id_of_changes: current_user.id)) | ||||||
| 
 | 
 | ||||||
|     respond_to do |format| |     respond_to do |format| | ||||||
|       format.js |       format.js | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| class OmniauthCallbacksController < Devise::OmniauthCallbacksController | class OmniauthCallbacksController < Devise::OmniauthCallbacksController | ||||||
|   Gitlab.config.omniauth_providers.each do |provider| |   Gitlab.config.omniauth.providers.each do |provider| | ||||||
|     define_method provider['name'] do |     define_method provider['name'] do | ||||||
|       handle_omniauth |       handle_omniauth | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  | @ -46,6 +46,10 @@ class ProjectsController < ProjectResourceController | ||||||
|         format.js |         format.js | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | 
 | ||||||
|  |   rescue Project::TransferError => ex | ||||||
|  |     @error = ex | ||||||
|  |     render :update_failed | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def show |   def show | ||||||
|  | @ -54,12 +58,12 @@ class ProjectsController < ProjectResourceController | ||||||
| 
 | 
 | ||||||
|     respond_to do |format| |     respond_to do |format| | ||||||
|       format.html do |       format.html do | ||||||
|          unless @project.empty_repo? |         unless @project.empty_repo? | ||||||
|            @last_push = current_user.recent_push(@project.id) |           @last_push = current_user.recent_push(@project.id) | ||||||
|            render :show |           render :show | ||||||
|          else |         else | ||||||
|            render "projects/empty" |           render "projects/empty" | ||||||
|          end |         end | ||||||
|       end |       end | ||||||
|       format.js |       format.js | ||||||
|     end |     end | ||||||
|  | @ -86,12 +90,18 @@ class ProjectsController < ProjectResourceController | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def graph |   def graph | ||||||
|     graph = Gitlab::Graph::JsonBuilder.new(project) |     respond_to do |format| | ||||||
| 
 |       format.html | ||||||
|     @days_json, @commits_json = graph.days_json, graph.commits_json |       format.json do | ||||||
|  |         graph = Gitlab::Graph::JsonBuilder.new(project) | ||||||
|  |         render :json => graph.to_json | ||||||
|  |       end | ||||||
|  |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def destroy |   def destroy | ||||||
|  |     return access_denied! unless can?(current_user, :remove_project, project) | ||||||
|  | 
 | ||||||
|     # Disable the UsersProject update_repository call, otherwise it will be |     # Disable the UsersProject update_repository call, otherwise it will be | ||||||
|     # called once for every person removed from the project |     # called once for every person removed from the project | ||||||
|     UsersProject.skip_callback(:destroy, :after, :update_repository) |     UsersProject.skip_callback(:destroy, :after, :update_repository) | ||||||
|  |  | ||||||
|  | @ -16,7 +16,7 @@ class SnippetsController < ProjectResourceController | ||||||
|   respond_to :html |   respond_to :html | ||||||
| 
 | 
 | ||||||
|   def index |   def index | ||||||
|     @snippets = @project.snippets |     @snippets = @project.snippets.fresh | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def new |   def new | ||||||
|  | @ -62,7 +62,7 @@ class SnippetsController < ProjectResourceController | ||||||
|     redirect_to project_snippets_path(@project) |     redirect_to project_snippets_path(@project) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def raw  |   def raw | ||||||
|     send_data( |     send_data( | ||||||
|       @snippet.content, |       @snippet.content, | ||||||
|       type: "text/plain", |       type: "text/plain", | ||||||
|  |  | ||||||
|  | @ -76,7 +76,7 @@ class CommitDecorator < ApplicationDecorator | ||||||
|     source_name = send "#{options[:source]}_name".to_sym |     source_name = send "#{options[:source]}_name".to_sym | ||||||
|     source_email = send "#{options[:source]}_email".to_sym |     source_email = send "#{options[:source]}_email".to_sym | ||||||
|     text = if options[:avatar] |     text = if options[:avatar] | ||||||
|             avatar = h.image_tag h.gravatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size] |             avatar = h.image_tag h.gravatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "" | ||||||
|             %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>} |             %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>} | ||||||
|           else |           else | ||||||
|             source_name |             source_name | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| require 'digest/md5' | require 'digest/md5' | ||||||
|  | require 'uri' | ||||||
| 
 | 
 | ||||||
| module ApplicationHelper | module ApplicationHelper | ||||||
| 
 | 
 | ||||||
|  | @ -30,13 +31,15 @@ module ApplicationHelper | ||||||
|     args.any? { |v| v.to_s.downcase == action_name } |     args.any? { |v| v.to_s.downcase == action_name } | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def gravatar_icon(user_email = '', size = 40) |   def gravatar_icon(user_email = '', size = nil) | ||||||
|     if Gitlab.config.disable_gravatar? || user_email.blank? |     size = 40 if size.nil? || size <= 0 | ||||||
|  | 
 | ||||||
|  |     if !Gitlab.config.gravatar.enabled || user_email.blank? | ||||||
|       'no_avatar.png' |       'no_avatar.png' | ||||||
|     else |     else | ||||||
|       gravatar_prefix = request.ssl? ? "https://secure" : "http://www" |       gravatar_url = request.ssl? ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url | ||||||
|       user_email.strip! |       user_email.strip! | ||||||
|       "#{gravatar_prefix}.gravatar.com/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=mm" |       sprintf(gravatar_url, {:hash => Digest::MD5.hexdigest(user_email.downcase), :email => URI.escape(user_email), :size => size}) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  | @ -45,7 +48,7 @@ module ApplicationHelper | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def web_app_url |   def web_app_url | ||||||
|     "#{request_protocol}://#{Gitlab.config.web_host}/" |     "#{request_protocol}://#{Gitlab.config.gitlab.host}/" | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def last_commit(project) |   def last_commit(project) | ||||||
|  | @ -92,6 +95,7 @@ module ApplicationHelper | ||||||
|       { label: "API Help", url: help_api_path }, |       { label: "API Help", url: help_api_path }, | ||||||
|       { label: "Markdown Help", url: help_markdown_path }, |       { label: "Markdown Help", url: help_markdown_path }, | ||||||
|       { label: "SSH Keys Help", url: help_ssh_path }, |       { label: "SSH Keys Help", url: help_ssh_path }, | ||||||
|  |       { label: "Gitlab Rake Tasks Help", url: help_raketasks_path }, | ||||||
|     ] |     ] | ||||||
| 
 | 
 | ||||||
|     project_nav = [] |     project_nav = [] | ||||||
|  |  | ||||||
|  | @ -4,28 +4,6 @@ module IssuesHelper | ||||||
|     project_issues_path project, params |     project_issues_path project, params | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def link_to_issue_assignee(issue) |  | ||||||
|     project = issue.project |  | ||||||
| 
 |  | ||||||
|     tm = project.team_member_by_id(issue.assignee_id) |  | ||||||
|     if tm |  | ||||||
|       link_to issue.assignee_name, project_team_member_path(project, tm), class: "author_link" |  | ||||||
|     else |  | ||||||
|       issue.assignee_name |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def link_to_issue_author(issue) |  | ||||||
|     project = issue.project |  | ||||||
| 
 |  | ||||||
|     tm = project.team_member_by_id(issue.author_id) |  | ||||||
|     if tm |  | ||||||
|       link_to issue.author_name, project_team_member_path(project, tm), class: "author_link" |  | ||||||
|     else |  | ||||||
|       issue.author_name |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def issue_css_classes issue |   def issue_css_classes issue | ||||||
|     classes = "issue" |     classes = "issue" | ||||||
|     classes << " closed" if issue.closed |     classes << " closed" if issue.closed | ||||||
|  | @ -52,4 +30,14 @@ module IssuesHelper | ||||||
|       open: "open" |       open: "open" | ||||||
|     } |     } | ||||||
|   end |   end | ||||||
|  | 
 | ||||||
|  |   def labels_autocomplete_source | ||||||
|  |     labels = @project.issues_labels.order('count DESC') | ||||||
|  |     labels = labels.map{ |l| { label: l.name, value: l.name } } | ||||||
|  |     labels.to_json | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def issues_active_milestones | ||||||
|  |     @project.milestones.active.order("id desc").all | ||||||
|  |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -1,26 +1,4 @@ | ||||||
| module MergeRequestsHelper | module MergeRequestsHelper | ||||||
|   def link_to_merge_request_assignee(merge_request) |  | ||||||
|     project = merge_request.project |  | ||||||
| 
 |  | ||||||
|     tm = project.team_member_by_id(merge_request.assignee_id) |  | ||||||
|     if tm |  | ||||||
|       link_to merge_request.assignee_name, project_team_member_path(project, tm), class: "author_link" |  | ||||||
|     else |  | ||||||
|       merge_request.assignee_name |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def link_to_merge_request_author(merge_request) |  | ||||||
|     project = merge_request.project |  | ||||||
| 
 |  | ||||||
|     tm = project.team_member_by_id(merge_request.author_id) |  | ||||||
|     if tm |  | ||||||
|       link_to merge_request.author_name, project_team_member_path(project, tm), class: "author_link" |  | ||||||
|     else |  | ||||||
|       merge_request.author_name |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def new_mr_path_from_push_event(event) |   def new_mr_path_from_push_event(event) | ||||||
|     new_project_merge_request_path( |     new_project_merge_request_path( | ||||||
|       event.project, |       event.project, | ||||||
|  | @ -39,7 +17,7 @@ module MergeRequestsHelper | ||||||
|     classes |     classes | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def ci_status_path |   def ci_build_details_path merge_request | ||||||
|     @project.gitlab_ci_service.commit_badge_path(@merge_request.last_commit.sha) |     merge_request.project.gitlab_ci_service.build_page(merge_request.last_commit.sha) | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -8,11 +8,49 @@ module ProjectsHelper | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def link_to_project project |   def link_to_project project | ||||||
|     link_to project.name, project |     link_to project do | ||||||
|  |       title = content_tag(:strong, project.name) | ||||||
|  | 
 | ||||||
|  |       if project.namespace | ||||||
|  |         namespace = content_tag(:span, "#{project.namespace.human_name} / ", class: 'tiny') | ||||||
|  |         title = namespace + title | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       title | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def link_to_member(project, author) | ||||||
|  |     return "(deleted)" unless author | ||||||
|  | 
 | ||||||
|  |     # Build avatar image tag | ||||||
|  |     avatar = image_tag(gravatar_icon(author.try(:email)), width: 16, class: "lil_av") | ||||||
|  | 
 | ||||||
|  |     # Build name strong tag | ||||||
|  |     name = content_tag :strong, author.name, class: 'author' | ||||||
|  | 
 | ||||||
|  |     author_html = avatar + name | ||||||
|  | 
 | ||||||
|  |     tm = project.team_member_by_id(author) | ||||||
|  | 
 | ||||||
|  |     content_tag :span, class: 'member-link' do | ||||||
|  |       if tm | ||||||
|  |         link_to author_html, project_team_member_path(project, tm), class: "author_link" | ||||||
|  |       else | ||||||
|  |         author_html | ||||||
|  |       end | ||||||
|  |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def tm_path team_member |   def tm_path team_member | ||||||
|     project_team_member_path(@project, team_member) |     project_team_member_path(@project, team_member) | ||||||
|   end |   end | ||||||
| end |  | ||||||
| 
 | 
 | ||||||
|  |   def project_title project | ||||||
|  |     if project.group | ||||||
|  |       project.name_with_namespace | ||||||
|  |     else | ||||||
|  |       project.name | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
|  |  | ||||||
|  | @ -72,7 +72,7 @@ module TabHelper | ||||||
|       return "active" if current_page?(controller: "projects", action: action, id: @project) |       return "active" if current_page?(controller: "projects", action: action, id: @project) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     if ['snippets', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name |     if ['snippets', 'services', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name | ||||||
|      "active" |      "active" | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  | @ -3,11 +3,11 @@ class Notify < ActionMailer::Base | ||||||
|   add_template_helper ApplicationHelper |   add_template_helper ApplicationHelper | ||||||
|   add_template_helper GitlabMarkdownHelper |   add_template_helper GitlabMarkdownHelper | ||||||
| 
 | 
 | ||||||
|   default_url_options[:host]     = Gitlab.config.web_host |   default_url_options[:host]     = Gitlab.config.gitlab.host | ||||||
|   default_url_options[:protocol] = Gitlab.config.web_protocol |   default_url_options[:protocol] = Gitlab.config.gitlab.protocol | ||||||
|   default_url_options[:port]     = Gitlab.config.web_port if Gitlab.config.web_custom_port? |   default_url_options[:port]     = Gitlab.config.gitlab.port if Gitlab.config.gitlab_on_non_standard_port? | ||||||
| 
 | 
 | ||||||
|   default from: Gitlab.config.email_from |   default from: Gitlab.config.gitlab.email_from | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -31,6 +31,7 @@ class Notify < ActionMailer::Base | ||||||
|   def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id) |   def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id) | ||||||
|     @issue = Issue.find issue_id |     @issue = Issue.find issue_id | ||||||
|     @issue_status = status |     @issue_status = status | ||||||
|  |     @project = @issue.project | ||||||
|     @updated_by = User.find updated_by_user_id |     @updated_by = User.find updated_by_user_id | ||||||
|     mail(to: recipient(recipient_id), |     mail(to: recipient(recipient_id), | ||||||
|         subject: subject("changed issue ##{@issue.id}", @issue.title)) |         subject: subject("changed issue ##{@issue.id}", @issue.title)) | ||||||
|  | @ -102,6 +103,12 @@ class Notify < ActionMailer::Base | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |   def project_was_moved_email(user_project_id) | ||||||
|  |     @users_project = UsersProject.find user_project_id | ||||||
|  |     @project = @users_project.project | ||||||
|  |     mail(to: @users_project.user.email, | ||||||
|  |          subject: subject("project was moved")) | ||||||
|  |   end | ||||||
| 
 | 
 | ||||||
|   # |   # | ||||||
|   # User |   # User | ||||||
|  |  | ||||||
|  | @ -17,9 +17,7 @@ class Ability | ||||||
| 
 | 
 | ||||||
|       # Rules based on role in project |       # Rules based on role in project | ||||||
|       if project.master_access_for?(user) |       if project.master_access_for?(user) | ||||||
|         # TODO: replace with master rules. |         rules << project_master_rules | ||||||
|         # Only allow project administration for namespace owners |  | ||||||
|         rules << project_admin_rules |  | ||||||
| 
 | 
 | ||||||
|       elsif project.dev_access_for?(user) |       elsif project.dev_access_for?(user) | ||||||
|         rules << project_dev_rules |         rules << project_dev_rules | ||||||
|  | @ -93,13 +91,16 @@ class Ability | ||||||
|         :admin_merge_request, |         :admin_merge_request, | ||||||
|         :admin_note, |         :admin_note, | ||||||
|         :accept_mr, |         :accept_mr, | ||||||
|         :admin_wiki |         :admin_wiki, | ||||||
|  |         :admin_project | ||||||
|       ] |       ] | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def project_admin_rules |     def project_admin_rules | ||||||
|       project_master_rules + [ |       project_master_rules + [ | ||||||
|         :admin_project |         :change_namespace, | ||||||
|  |         :rename_project, | ||||||
|  |         :remove_project | ||||||
|       ] |       ] | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -87,14 +87,10 @@ class Commit | ||||||
|       last = project.commit(from.try(:strip)) |       last = project.commit(from.try(:strip)) | ||||||
| 
 | 
 | ||||||
|       if first && last |       if first && last | ||||||
|         commits = [first, last].sort_by(&:created_at) |         result[:same] = (first.id == last.id) | ||||||
|         younger = commits.first |         result[:commits] = project.repo.commits_between(last.id, first.id).map {|c| Commit.new(c)} | ||||||
|         older = commits.last |         result[:diffs] = project.repo.diff(last.id, first.id) rescue [] | ||||||
| 
 |         result[:commit] = Commit.new(first) | ||||||
|         result[:same] = (younger.id == older.id) |  | ||||||
|         result[:commits] = project.repo.commits_between(younger.id, older.id).map {|c| Commit.new(c)} |  | ||||||
|         result[:diffs] = project.repo.diff(younger.id, older.id) rescue [] |  | ||||||
|         result[:commit] = Commit.new(older) |  | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       result |       result | ||||||
|  | @ -163,6 +159,8 @@ class Commit | ||||||
|     while !lines.first.start_with?("diff --git") do |     while !lines.first.start_with?("diff --git") do | ||||||
|       lines.shift |       lines.shift | ||||||
|     end |     end | ||||||
|  |     lines.pop if lines.last =~ /^[\d.]+$/ # Git version | ||||||
|  |     lines.pop if lines.last == "-- "      # end of diff | ||||||
|     lines.join("\n") |     lines.join("\n") | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -15,6 +15,7 @@ | ||||||
| # | # | ||||||
| 
 | 
 | ||||||
| class Event < ActiveRecord::Base | class Event < ActiveRecord::Base | ||||||
|  |   include NoteEvent | ||||||
|   include PushEvent |   include PushEvent | ||||||
| 
 | 
 | ||||||
|   attr_accessible :project, :action, :data, :author_id, :project_id, |   attr_accessible :project, :action, :data, :author_id, :project_id, | ||||||
|  | @ -58,12 +59,14 @@ class Event < ActiveRecord::Base | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   # Next events currently enabled for system |   def proper? | ||||||
|   #  - push |     if push? | ||||||
|   #  - new issue |       true | ||||||
|   #  - merge request |     elsif membership_changed? | ||||||
|   def allowed? |       true | ||||||
|     push? || issue? || merge_request? || membership_changed? |     else | ||||||
|  |       (issue? || merge_request? || note? || milestone?) && target | ||||||
|  |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def project_name |   def project_name | ||||||
|  | @ -94,6 +97,14 @@ class Event < ActiveRecord::Base | ||||||
|     action == self.class::Reopened |     action == self.class::Reopened | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   def milestone? | ||||||
|  |     target_type == "Milestone" | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def note? | ||||||
|  |     target_type == "Note" | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   def issue? |   def issue? | ||||||
|     target_type == "Issue" |     target_type == "Issue" | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  | @ -36,4 +36,22 @@ class GitlabCiService < Service | ||||||
|   def commit_badge_path sha |   def commit_badge_path sha | ||||||
|     project_url + "/status?sha=#{sha}" |     project_url + "/status?sha=#{sha}" | ||||||
|   end |   end | ||||||
|  | 
 | ||||||
|  |   def commit_status_path sha | ||||||
|  |     project_url + "/builds/#{sha}/status.json?token=#{token}" | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def commit_status sha | ||||||
|  |     response = HTTParty.get(commit_status_path(sha)) | ||||||
|  | 
 | ||||||
|  |     if response.code == 200 and response["status"] | ||||||
|  |       response["status"] | ||||||
|  |     else | ||||||
|  |       :error | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def build_page sha | ||||||
|  |     project_url + "/builds/#{sha}" | ||||||
|  |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -204,7 +204,7 @@ class MergeRequest < ActiveRecord::Base | ||||||
| 
 | 
 | ||||||
|   def mr_and_commit_notes |   def mr_and_commit_notes | ||||||
|     commit_ids = commits.map(&:id) |     commit_ids = commits.map(&:id) | ||||||
|     Note.where("(noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR (noteable_type = 'Commit' AND noteable_id IN (:commit_ids))", mr_id: id, commit_ids: commit_ids) |     Note.where("(noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR (noteable_type = 'Commit' AND commit_id IN (:commit_ids))", mr_id: id, commit_ids: commit_ids) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   # Returns the raw diff for this merge request |   # Returns the raw diff for this merge request | ||||||
|  | @ -220,4 +220,8 @@ class MergeRequest < ActiveRecord::Base | ||||||
|   def to_patch |   def to_patch | ||||||
|     project.repo.git.format_patch({timeout: 30, raise: true, stdout: true}, "#{target_branch}..#{source_branch}") |     project.repo.git.format_patch({timeout: 30, raise: true, stdout: true}, "#{target_branch}..#{source_branch}") | ||||||
|   end |   end | ||||||
|  | 
 | ||||||
|  |   def last_commit_short_sha | ||||||
|  |     @last_commit_short_sha ||= last_commit.sha[0..10] | ||||||
|  |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -13,18 +13,26 @@ | ||||||
| # | # | ||||||
| 
 | 
 | ||||||
| class Milestone < ActiveRecord::Base | class Milestone < ActiveRecord::Base | ||||||
|   attr_accessible :title, :description, :due_date, :closed |   attr_accessible :title, :description, :due_date, :closed, :author_id_of_changes | ||||||
|  |   attr_accessor :author_id_of_changes | ||||||
| 
 | 
 | ||||||
|   belongs_to :project |   belongs_to :project | ||||||
|   has_many :issues |   has_many :issues | ||||||
|   has_many :merge_requests |   has_many :merge_requests | ||||||
| 
 | 
 | ||||||
|  |   scope :active, where(closed: false) | ||||||
|  |   scope :closed, where(closed: true) | ||||||
|  | 
 | ||||||
|   validates :title, presence: true |   validates :title, presence: true | ||||||
|   validates :project, presence: true |   validates :project, presence: true | ||||||
|   validates :closed, inclusion: { in: [true, false] } |   validates :closed, inclusion: { in: [true, false] } | ||||||
| 
 | 
 | ||||||
|   def self.active |   def expired? | ||||||
|     where("due_date > ? OR due_date IS NULL", Date.today) |     if due_date | ||||||
|  |       due_date < Date.today | ||||||
|  |     else | ||||||
|  |       false | ||||||
|  |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def participants |   def participants | ||||||
|  | @ -52,4 +60,20 @@ class Milestone < ActiveRecord::Base | ||||||
|   def expires_at |   def expires_at | ||||||
|     "expires at #{due_date.stamp("Aug 21, 2011")}" if due_date |     "expires at #{due_date.stamp("Aug 21, 2011")}" if due_date | ||||||
|   end |   end | ||||||
|  | 
 | ||||||
|  |   def can_be_closed? | ||||||
|  |     open? && issues.opened.count.zero? | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def is_empty? | ||||||
|  |     total_items_count.zero? | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def open? | ||||||
|  |     !closed | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def author_id | ||||||
|  |     author_id_of_changes | ||||||
|  |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -48,23 +48,30 @@ class Namespace < ActiveRecord::Base | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def ensure_dir_exist |   def ensure_dir_exist | ||||||
|     namespace_dir_path = File.join(Gitlab.config.git_base_path, path) |     namespace_dir_path = File.join(Gitlab.config.gitolite.repos_path, path) | ||||||
|     system("mkdir -m 770 #{namespace_dir_path}") unless File.exists?(namespace_dir_path) |     system("mkdir -m 770 #{namespace_dir_path}") unless File.exists?(namespace_dir_path) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def move_dir |   def move_dir | ||||||
|     if path_changed? |     if path_changed? | ||||||
|       old_path = File.join(Gitlab.config.git_base_path, path_was) |       old_path = File.join(Gitlab.config.gitolite.repos_path, path_was) | ||||||
|       new_path = File.join(Gitlab.config.git_base_path, path) |       new_path = File.join(Gitlab.config.gitolite.repos_path, path) | ||||||
|       if File.exists?(new_path) |       if File.exists?(new_path) | ||||||
|         raise "Already exists" |         raise "Already exists" | ||||||
|       end |       end | ||||||
|       system("mv #{old_path} #{new_path}") | 
 | ||||||
|  |       if system("mv #{old_path} #{new_path}") | ||||||
|  |         send_update_instructions | ||||||
|  |       end | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def rm_dir |   def rm_dir | ||||||
|     dir_path = File.join(Gitlab.config.git_base_path, path) |     dir_path = File.join(Gitlab.config.gitolite.repos_path, path) | ||||||
|     system("rm -rf #{dir_path}") |     system("rm -rf #{dir_path}") | ||||||
|   end |   end | ||||||
|  | 
 | ||||||
|  |   def send_update_instructions | ||||||
|  |     projects.each(&:send_move_instructions) | ||||||
|  |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ require 'file_size_validator' | ||||||
| 
 | 
 | ||||||
| class Note < ActiveRecord::Base | class Note < ActiveRecord::Base | ||||||
|   attr_accessible :note, :noteable, :noteable_id, :noteable_type, :project_id, |   attr_accessible :note, :noteable, :noteable_id, :noteable_type, :project_id, | ||||||
|                   :attachment, :line_code |                   :attachment, :line_code, :commit_id | ||||||
| 
 | 
 | ||||||
|   attr_accessor :notify |   attr_accessor :notify | ||||||
|   attr_accessor :notify_author |   attr_accessor :notify_author | ||||||
|  | @ -35,10 +35,14 @@ class Note < ActiveRecord::Base | ||||||
|   validates :line_code, format: { with: /\A\d+_\d+_\d+\Z/ }, allow_blank: true |   validates :line_code, format: { with: /\A\d+_\d+_\d+\Z/ }, allow_blank: true | ||||||
|   validates :attachment, file_size: { maximum: 10.megabytes.to_i } |   validates :attachment, file_size: { maximum: 10.megabytes.to_i } | ||||||
| 
 | 
 | ||||||
|  |   validates :noteable_id, presence: true, if: ->(n) { n.noteable_type.present? && n.noteable_type != 'Commit' } | ||||||
|  |   validates :commit_id, presence: true, if: ->(n) { n.noteable_type == 'Commit' } | ||||||
|  | 
 | ||||||
|   mount_uploader :attachment, AttachmentUploader |   mount_uploader :attachment, AttachmentUploader | ||||||
| 
 | 
 | ||||||
|   # Scopes |   # Scopes | ||||||
|   scope :common, ->{ where(noteable_id: nil) } |   scope :for_commits, ->{ where(noteable_type: "Commit") } | ||||||
|  |   scope :common, ->{ where(noteable_id: nil, commit_id: nil) } | ||||||
|   scope :today, ->{ where("created_at >= :date", date: Date.today) } |   scope :today, ->{ where("created_at >= :date", date: Date.today) } | ||||||
|   scope :last_week, ->{ where("created_at  >= :date", date: (Date.today - 7.days)) } |   scope :last_week, ->{ where("created_at  >= :date", date: (Date.today - 7.days)) } | ||||||
|   scope :since, ->(day) { where("created_at  >= :date", date: (day)) } |   scope :since, ->(day) { where("created_at  >= :date", date: (day)) } | ||||||
|  | @ -122,7 +126,7 @@ class Note < ActiveRecord::Base | ||||||
|   # override to return commits, which are not active record |   # override to return commits, which are not active record | ||||||
|   def noteable |   def noteable | ||||||
|     if for_commit? |     if for_commit? | ||||||
|       project.commit(noteable_id) |       project.commit(commit_id) | ||||||
|     else |     else | ||||||
|       super |       super | ||||||
|     end |     end | ||||||
|  | @ -151,4 +155,12 @@ class Note < ActiveRecord::Base | ||||||
|   def votable? |   def votable? | ||||||
|     for_issue? || (for_merge_request? && !for_diff_line?) |     for_issue? || (for_merge_request? && !for_diff_line?) | ||||||
|   end |   end | ||||||
|  | 
 | ||||||
|  |   def noteable_type_name | ||||||
|  |     if noteable_type.present? | ||||||
|  |       noteable_type.downcase | ||||||
|  |     else | ||||||
|  |       "wall" | ||||||
|  |     end | ||||||
|  |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -25,6 +25,9 @@ class Project < ActiveRecord::Base | ||||||
|   include PushObserver |   include PushObserver | ||||||
|   include Authority |   include Authority | ||||||
|   include Team |   include Team | ||||||
|  |   include NamespacedProject | ||||||
|  | 
 | ||||||
|  |   class TransferError < StandardError; end | ||||||
| 
 | 
 | ||||||
|   attr_accessible :name, :path, :description, :default_branch, :issues_enabled, |   attr_accessible :name, :path, :description, :default_branch, :issues_enabled, | ||||||
|                   :wall_enabled, :merge_requests_enabled, :wiki_enabled, as: [:default, :admin] |                   :wall_enabled, :merge_requests_enabled, :wiki_enabled, as: [:default, :admin] | ||||||
|  | @ -36,6 +39,10 @@ class Project < ActiveRecord::Base | ||||||
|   # Relations |   # Relations | ||||||
|   belongs_to :group, foreign_key: "namespace_id", conditions: "type = 'Group'" |   belongs_to :group, foreign_key: "namespace_id", conditions: "type = 'Group'" | ||||||
|   belongs_to :namespace |   belongs_to :namespace | ||||||
|  | 
 | ||||||
|  |   # TODO: replace owner with creator. | ||||||
|  |   # With namespaces a project owner will be a namespace owner | ||||||
|  |   # so this field makes sense only for global projects | ||||||
|   belongs_to :owner, class_name: "User" |   belongs_to :owner, class_name: "User" | ||||||
|   has_many :users,          through: :users_projects |   has_many :users,          through: :users_projects | ||||||
|   has_many :events,         dependent: :destroy |   has_many :events,         dependent: :destroy | ||||||
|  | @ -97,7 +104,7 @@ class Project < ActiveRecord::Base | ||||||
|         namespace_id = Namespace.find_by_path(id.first).id |         namespace_id = Namespace.find_by_path(id.first).id | ||||||
|         where(namespace_id: namespace_id).find_by_path(id.last) |         where(namespace_id: namespace_id).find_by_path(id.last) | ||||||
|       else |       else | ||||||
|         find_by_path(id) |         where(path: id, namespace_id: nil).last | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  | @ -172,7 +179,7 @@ class Project < ActiveRecord::Base | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def repo_name |   def repo_name | ||||||
|     denied_paths = %w(gitolite-admin groups projects dashboard) |     denied_paths = %w(gitolite-admin admin dashboard groups help profile projects search) | ||||||
| 
 | 
 | ||||||
|     if denied_paths.include?(path) |     if denied_paths.include?(path) | ||||||
|       errors.add(:path, "like #{path} is not allowed") |       errors.add(:path, "like #{path} is not allowed") | ||||||
|  | @ -188,7 +195,7 @@ class Project < ActiveRecord::Base | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def web_url |   def web_url | ||||||
|     [Gitlab.config.url, path].join("/") |     [Gitlab.config.gitlab.url, path_with_namespace].join("/") | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def common_notes |   def common_notes | ||||||
|  | @ -196,15 +203,15 @@ class Project < ActiveRecord::Base | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def build_commit_note(commit) |   def build_commit_note(commit) | ||||||
|     notes.new(noteable_id: commit.id, noteable_type: "Commit") |     notes.new(commit_id: commit.id, noteable_type: "Commit") | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def commit_notes(commit) |   def commit_notes(commit) | ||||||
|     notes.where(noteable_id: commit.id, noteable_type: "Commit").where('line_code IS NULL OR line_code = ""') |     notes.where(commit_id: commit.id, noteable_type: "Commit").where('line_code IS NULL OR line_code = ""') | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def commit_line_notes(commit) |   def commit_line_notes(commit) | ||||||
|     notes.where(noteable_id: commit.id, noteable_type: "Commit").where("line_code IS NOT NULL") |     notes.where(commit_id: commit.id, noteable_type: "Commit").where("line_code IS NOT NULL") | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def public? |   def public? | ||||||
|  | @ -239,51 +246,11 @@ class Project < ActiveRecord::Base | ||||||
|     gitlab_ci_service && gitlab_ci_service.active |     gitlab_ci_service && gitlab_ci_service.active | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def path_with_namespace |  | ||||||
|     if namespace |  | ||||||
|       namespace.path + '/' + path |  | ||||||
|     else |  | ||||||
|       path |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   # For compatibility with old code |   # For compatibility with old code | ||||||
|   def code |   def code | ||||||
|     path |     path | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def transfer(new_namespace) |  | ||||||
|     Project.transaction do |  | ||||||
|       old_namespace = namespace |  | ||||||
|       self.namespace = new_namespace |  | ||||||
| 
 |  | ||||||
|       old_dir = old_namespace.try(:path) || '' |  | ||||||
|       new_dir = new_namespace.try(:path) || '' |  | ||||||
| 
 |  | ||||||
|       old_repo = if old_dir.present? |  | ||||||
|                    File.join(old_dir, self.path) |  | ||||||
|                  else |  | ||||||
|                    self.path |  | ||||||
|                  end |  | ||||||
| 
 |  | ||||||
|       Gitlab::ProjectMover.new(self, old_dir, new_dir).execute |  | ||||||
| 
 |  | ||||||
|       git_host.move_repository(old_repo, self) |  | ||||||
| 
 |  | ||||||
|       save! |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def name_with_namespace |  | ||||||
|     @name_with_namespace ||= begin |  | ||||||
|                                if namespace |  | ||||||
|                                  namespace.human_name + " / " + name |  | ||||||
|                                else |  | ||||||
|                                  name |  | ||||||
|                                end |  | ||||||
|                              end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def items_for entity |   def items_for entity | ||||||
|     case entity |     case entity | ||||||
|     when 'issue' then |     when 'issue' then | ||||||
|  | @ -293,7 +260,9 @@ class Project < ActiveRecord::Base | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def namespace_owner |   def send_move_instructions | ||||||
|     namespace.try(:owner) |     self.users_projects.each do |member| | ||||||
|  |       Notify.project_was_moved_email(member.id).deliver | ||||||
|  |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -22,7 +22,7 @@ class Snippet < ActiveRecord::Base | ||||||
|   belongs_to :author, class_name: "User" |   belongs_to :author, class_name: "User" | ||||||
|   has_many :notes, as: :noteable, dependent: :destroy |   has_many :notes, as: :noteable, dependent: :destroy | ||||||
| 
 | 
 | ||||||
|   delegate :name, :email, to: :author, prefix: true |   delegate :name, :email, to: :author, prefix: true, allow_nil: true | ||||||
| 
 | 
 | ||||||
|   validates :author, presence: true |   validates :author, presence: true | ||||||
|   validates :project, presence: true |   validates :project, presence: true | ||||||
|  |  | ||||||
|  | @ -56,12 +56,12 @@ class User < ActiveRecord::Base | ||||||
|   has_many :issues, foreign_key: :author_id, dependent: :destroy |   has_many :issues, foreign_key: :author_id, dependent: :destroy | ||||||
|   has_many :notes, foreign_key: :author_id, dependent: :destroy |   has_many :notes, foreign_key: :author_id, dependent: :destroy | ||||||
|   has_many :merge_requests, foreign_key: :author_id, dependent: :destroy |   has_many :merge_requests, foreign_key: :author_id, dependent: :destroy | ||||||
|   has_many :my_own_projects, class_name: "Project", foreign_key: :owner_id |  | ||||||
|   has_many :events, class_name: "Event", foreign_key: :author_id, dependent: :destroy |   has_many :events, class_name: "Event", foreign_key: :author_id, dependent: :destroy | ||||||
|   has_many :recent_events, class_name: "Event", foreign_key: :author_id, order: "id DESC" |   has_many :recent_events, class_name: "Event", foreign_key: :author_id, order: "id DESC" | ||||||
|   has_many :assigned_issues, class_name: "Issue", foreign_key: :assignee_id, dependent: :destroy |   has_many :assigned_issues, class_name: "Issue", foreign_key: :assignee_id, dependent: :destroy | ||||||
|   has_many :assigned_merge_requests, class_name: "MergeRequest", foreign_key: :assignee_id, dependent: :destroy |   has_many :assigned_merge_requests, class_name: "MergeRequest", foreign_key: :assignee_id, dependent: :destroy | ||||||
| 
 | 
 | ||||||
|  |   validates :name, presence: true | ||||||
|   validates :bio, length: { within: 0..255 } |   validates :bio, length: { within: 0..255 } | ||||||
|   validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider} |   validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider} | ||||||
|   validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0} |   validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0} | ||||||
|  | @ -123,16 +123,4 @@ class User < ActiveRecord::Base | ||||||
|       self.password = self.password_confirmation = Devise.friendly_token.first(8) |       self.password = self.password_confirmation = Devise.friendly_token.first(8) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 |  | ||||||
|   def authorized_groups |  | ||||||
|     @authorized_groups ||= begin |  | ||||||
|                            groups = Group.where(id: self.projects.pluck(:namespace_id)).all |  | ||||||
|                            groups = groups + self.groups |  | ||||||
|                            groups.uniq |  | ||||||
|                          end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def authorized_projects |  | ||||||
|     Project.authorized_for(self) |  | ||||||
|   end |  | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -28,6 +28,7 @@ class UsersProject < ActiveRecord::Base | ||||||
| 
 | 
 | ||||||
|   validates :user, presence: true |   validates :user, presence: true | ||||||
|   validates :user_id, uniqueness: { :scope => [:project_id], message: "already exists in project" } |   validates :user_id, uniqueness: { :scope => [:project_id], message: "already exists in project" } | ||||||
|  |   validates :project_access, inclusion: { in: [GUEST, REPORTER, DEVELOPER, MASTER] }, presence: true | ||||||
|   validates :project, presence: true |   validates :project, presence: true | ||||||
| 
 | 
 | ||||||
|   delegate :name, :email, to: :user, prefix: true |   delegate :name, :email, to: :user, prefix: true | ||||||
|  |  | ||||||
|  | @ -1,18 +1,27 @@ | ||||||
| class ActivityObserver < ActiveRecord::Observer | class ActivityObserver < ActiveRecord::Observer | ||||||
|   observe :issue, :merge_request |   observe :issue, :merge_request, :note, :milestone | ||||||
| 
 | 
 | ||||||
|   def after_create(record) |   def after_create(record) | ||||||
|     Event.create( |     event_author_id = record.author_id | ||||||
|       project: record.project, | 
 | ||||||
|       target_id: record.id, |     # Skip status notes | ||||||
|       target_type: record.class.name, |     if record.kind_of?(Note) && record.note.include?("_Status changed to ") | ||||||
|       action: Event.determine_action(record), |       return true | ||||||
|       author_id: record.author_id |     end | ||||||
|     ) | 
 | ||||||
|  |     if event_author_id | ||||||
|  |       Event.create( | ||||||
|  |         project: record.project, | ||||||
|  |         target_id: record.id, | ||||||
|  |         target_type: record.class.name, | ||||||
|  |         action: Event.determine_action(record), | ||||||
|  |         author_id: event_author_id | ||||||
|  |       ) | ||||||
|  |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def after_save(record) |   def after_save(record) | ||||||
|     if record.changed.include?("closed")  |     if record.changed.include?("closed") && record.author_id_of_changes | ||||||
|       Event.create( |       Event.create( | ||||||
|         project: record.project, |         project: record.project, | ||||||
|         target_id: record.id, |         target_id: record.id, | ||||||
|  |  | ||||||
|  | @ -16,7 +16,7 @@ class IssueObserver < ActiveRecord::Observer | ||||||
|     if status |     if status | ||||||
|       Note.create_status_change_note(issue, current_user, status) |       Note.create_status_change_note(issue, current_user, status) | ||||||
|       [issue.author, issue.assignee].compact.each do |recipient| |       [issue.author, issue.assignee].compact.each do |recipient| | ||||||
|         Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user) |         Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user.id).deliver | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  | @ -21,7 +21,7 @@ class NoteObserver < ActiveRecord::Observer | ||||||
|   # Notifies the whole team except the author of note |   # Notifies the whole team except the author of note | ||||||
|   def notify_team(note) |   def notify_team(note) | ||||||
|     # Note: wall posts are not "attached" to anything, so fall back to "Wall" |     # Note: wall posts are not "attached" to anything, so fall back to "Wall" | ||||||
|     noteable_type = note.noteable_type || "Wall" |     noteable_type = note.noteable_type.presence || "Wall" | ||||||
|     notify_method = "note_#{noteable_type.underscore}_email".to_sym |     notify_method = "note_#{noteable_type.underscore}_email".to_sym | ||||||
| 
 | 
 | ||||||
|     if Notify.respond_to? notify_method |     if Notify.respond_to? notify_method | ||||||
|  |  | ||||||
|  | @ -3,7 +3,8 @@ class ProjectObserver < ActiveRecord::Observer | ||||||
|     project.update_repository |     project.update_repository | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def after_save(project) |   def after_update(project) | ||||||
|  |     project.send_move_instructions if project.namespace_id_changed? | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def after_destroy(project) |   def after_destroy(project) | ||||||
|  |  | ||||||
|  | @ -47,7 +47,7 @@ module Account | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def cared_merge_requests |   def cared_merge_requests | ||||||
|     MergeRequest.where("author_id = :id or assignee_id = :id", id: self.id).opened |     MergeRequest.where("author_id = :id or assignee_id = :id", id: self.id) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def project_ids |   def project_ids | ||||||
|  | @ -105,4 +105,20 @@ module Account | ||||||
|   def namespace_id |   def namespace_id | ||||||
|     namespace.try :id |     namespace.try :id | ||||||
|   end |   end | ||||||
|  | 
 | ||||||
|  |   def authorized_groups | ||||||
|  |     @authorized_groups ||= begin | ||||||
|  |                            groups = Group.where(id: self.projects.pluck(:namespace_id)).all | ||||||
|  |                            groups = groups + self.groups | ||||||
|  |                            groups.uniq | ||||||
|  |                          end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def authorized_projects | ||||||
|  |     Project.authorized_for(self) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def my_own_projects | ||||||
|  |     Project.personal(self) | ||||||
|  |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -0,0 +1,59 @@ | ||||||
|  | module NamespacedProject | ||||||
|  |   def transfer(new_namespace) | ||||||
|  |     Project.transaction do | ||||||
|  |       old_namespace = namespace | ||||||
|  |       self.namespace = new_namespace | ||||||
|  | 
 | ||||||
|  |       old_dir = old_namespace.try(:path) || '' | ||||||
|  |       new_dir = new_namespace.try(:path) || '' | ||||||
|  | 
 | ||||||
|  |       old_repo = if old_dir.present? | ||||||
|  |                    File.join(old_dir, self.path) | ||||||
|  |                  else | ||||||
|  |                    self.path | ||||||
|  |                  end | ||||||
|  | 
 | ||||||
|  |       if Project.where(path: self.path, namespace_id: new_namespace.try(:id)).present? | ||||||
|  |         raise TransferError.new("Project with same path in target namespace already exists") | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       Gitlab::ProjectMover.new(self, old_dir, new_dir).execute | ||||||
|  | 
 | ||||||
|  |       git_host.move_repository(old_repo, self) | ||||||
|  | 
 | ||||||
|  |       save! | ||||||
|  |     end | ||||||
|  |   rescue Gitlab::ProjectMover::ProjectMoveError => ex | ||||||
|  |     raise TransferError.new(ex.message) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def name_with_namespace | ||||||
|  |     @name_with_namespace ||= begin | ||||||
|  |                                if namespace | ||||||
|  |                                  namespace.human_name + " / " + name | ||||||
|  |                                else | ||||||
|  |                                  name | ||||||
|  |                                end | ||||||
|  |                              end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def namespace_owner | ||||||
|  |     namespace.try(:owner) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def chief | ||||||
|  |     if namespace | ||||||
|  |       namespace_owner | ||||||
|  |     else | ||||||
|  |       owner | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def path_with_namespace | ||||||
|  |     if namespace | ||||||
|  |       namespace.path + '/' + path | ||||||
|  |     else | ||||||
|  |       path | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -0,0 +1,37 @@ | ||||||
|  | module NoteEvent | ||||||
|  |   def note_commit_id | ||||||
|  |     target.commit_id | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def note_short_commit_id | ||||||
|  |     note_commit_id[0..8] | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def note_commit? | ||||||
|  |     target.noteable_type == "Commit" | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def note_target | ||||||
|  |     target.noteable | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def note_target_id | ||||||
|  |     if note_commit? | ||||||
|  |       target.commit_id | ||||||
|  |     else | ||||||
|  |       target.noteable_id.to_s | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def wall_note? | ||||||
|  |     target.noteable_type.blank? | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def note_target_type | ||||||
|  |     if target.noteable_type.present? | ||||||
|  |       target.noteable_type.titleize | ||||||
|  |     else | ||||||
|  |       "Wall" | ||||||
|  |     end.downcase | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -114,7 +114,7 @@ module PushObserver | ||||||
|         id: commit.id, |         id: commit.id, | ||||||
|         message: commit.safe_message, |         message: commit.safe_message, | ||||||
|         timestamp: commit.date.xmlschema, |         timestamp: commit.date.xmlschema, | ||||||
|         url: "#{Gitlab.config.url}/#{path}/commits/#{commit.id}", |         url: "#{Gitlab.config.gitlab.url}/#{path_with_namespace}/commit/#{commit.id}", | ||||||
|         author: { |         author: { | ||||||
|           name: commit.author_name, |           name: commit.author_name, | ||||||
|           email: commit.author_email |           email: commit.author_email | ||||||
|  |  | ||||||
|  | @ -45,8 +45,22 @@ module Repository | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def has_post_receive_file? |   def has_post_receive_file? | ||||||
|     hook_file = File.join(path_to_repo, 'hooks', 'post-receive') |     !!hook_file | ||||||
|     File.exists?(hook_file) |   end | ||||||
|  | 
 | ||||||
|  |   def valid_post_receive_file? | ||||||
|  |     valid_hook_file == hook_file | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def valid_hook_file | ||||||
|  |     @valid_hook_file ||= File.read(Rails.root.join('lib', 'hooks', 'post-receive')) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def hook_file | ||||||
|  |     @hook_file ||= begin | ||||||
|  |                      hook_path = File.join(path_to_repo, 'hooks', 'post-receive') | ||||||
|  |                      File.read(hook_path) if File.exists?(hook_path) | ||||||
|  |                    end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   # Returns an Array of branch names |   # Returns an Array of branch names | ||||||
|  | @ -83,7 +97,7 @@ module Repository | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def path_to_repo |   def path_to_repo | ||||||
|     File.join(Gitlab.config.git_base_path, "#{path_with_namespace}.git") |     File.join(Gitlab.config.gitolite.repos_path, "#{path_with_namespace}.git") | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def namespace_dir |   def namespace_dir | ||||||
|  | @ -185,7 +199,7 @@ module Repository | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def http_url_to_repo |   def http_url_to_repo | ||||||
|     http_url = [Gitlab.config.url, "/", path_with_namespace, ".git"].join('') |     http_url = [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('') | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   # Check if current branch name is marked as protected in the system |   # Check if current branch name is marked as protected in the system | ||||||
|  |  | ||||||
|  | @ -1,12 +0,0 @@ | ||||||
| = form_for [:admin, @group] do |f| |  | ||||||
|   - if @group.errors.any? |  | ||||||
|     .alert-message.block-message.error |  | ||||||
|       %span= @group.errors.full_messages.first |  | ||||||
|   .clearfix.group_name_holder |  | ||||||
|     = f.label :name do |  | ||||||
|       Group name is |  | ||||||
|     .input |  | ||||||
|       = f.text_field :name, placeholder: "Example Group", class: "xxlarge" |  | ||||||
| 
 |  | ||||||
|   .form-actions |  | ||||||
|     = f.submit 'Save group', class: "btn save-btn" |  | ||||||
|  | @ -1,3 +1,28 @@ | ||||||
| %h3.page_title Edit Group | %h3.page_title Rename Group | ||||||
| %br | %hr | ||||||
| = render 'form' | = form_for [:admin, @group] do |f| | ||||||
|  |   - if @group.errors.any? | ||||||
|  |     .alert-message.block-message.error | ||||||
|  |       %span= @group.errors.full_messages.first | ||||||
|  |   .clearfix.group_name_holder | ||||||
|  |     = f.label :name do | ||||||
|  |       Group name is | ||||||
|  |     .input | ||||||
|  |       = f.text_field :name, placeholder: "Example Group", class: "xxlarge" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   .clearfix.group_name_holder | ||||||
|  |     = f.label :path do | ||||||
|  |       %span.cred Group path is | ||||||
|  |     .input | ||||||
|  |       = f.text_field :path, placeholder: "example-group", class: "xxlarge danger" | ||||||
|  |       %ul.cred | ||||||
|  |         %li Changing group path can have unintended side effects. | ||||||
|  |         %li Renaming group path will rename directory for all related projects | ||||||
|  |         %li It will change web url for access group and group projects. | ||||||
|  |         %li It will change the git path to repositories under this group. | ||||||
|  | 
 | ||||||
|  |   .form-actions | ||||||
|  |     = f.submit 'Rename group', class: "btn danger" | ||||||
|  |     = link_to  'Cancel', admin_groups_path, class: "btn cancel-btn" | ||||||
|  |  | ||||||
|  | @ -12,17 +12,24 @@ | ||||||
| 
 | 
 | ||||||
| %table | %table | ||||||
|   %thead |   %thead | ||||||
|     %th Name |     %tr | ||||||
|     %th Path |       %th | ||||||
|     %th Projects |         Name | ||||||
|     %th Edit |         %i.icon-sort-down | ||||||
|     %th.cred Danger Zone! |       %th Path | ||||||
|  |       %th Projects | ||||||
|  |       %th Owner | ||||||
|  |       %th.cred Danger Zone! | ||||||
| 
 | 
 | ||||||
|   - @groups.each do |group| |   - @groups.each do |group| | ||||||
|     %tr |     %tr | ||||||
|       %td= link_to group.name, [:admin, group] |       %td | ||||||
|  |         %strong= link_to group.name, [:admin, group] | ||||||
|       %td= group.path |       %td= group.path | ||||||
|       %td= group.projects.count |       %td= group.projects.count | ||||||
|       %td= link_to 'Edit', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn small" |       %td | ||||||
|       %td.bgred= link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn small danger" |         = link_to group.owner_name, admin_user_path(group.owner_id) | ||||||
|  |       %td.bgred | ||||||
|  |         = link_to 'Rename', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn small" | ||||||
|  |         = link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn small danger" | ||||||
| = paginate @groups, theme: "admin" | = paginate @groups, theme: "admin" | ||||||
|  |  | ||||||
|  | @ -1,8 +1,5 @@ | ||||||
| %h3.page_title | %h3.page_title | ||||||
|   Group: #{@group.name} |   Group: #{@group.name} | ||||||
|   = link_to edit_admin_group_path(@group), class: "btn right" do |  | ||||||
|     %i.icon-edit |  | ||||||
|     Edit |  | ||||||
| 
 | 
 | ||||||
| %br | %br | ||||||
| %table.zebra-striped | %table.zebra-striped | ||||||
|  | @ -16,36 +13,64 @@ | ||||||
|         Name: |         Name: | ||||||
|     %td |     %td | ||||||
|       = @group.name |       = @group.name | ||||||
|  |         | ||||||
|  |       = link_to edit_admin_group_path(@group), class: "btn btn-small right" do | ||||||
|  |         %i.icon-edit | ||||||
|  |         Rename | ||||||
|   %tr |   %tr | ||||||
|     %td |     %td | ||||||
|       %b |       %b | ||||||
|         Path: |         Path: | ||||||
|     %td |     %td | ||||||
|       %span.monospace= File.join(Gitlab.config.git_base_path, @group.path) |       %span.monospace= File.join(Gitlab.config.gitolite.repos_path, @group.path) | ||||||
|   %tr |   %tr | ||||||
|     %td |     %td | ||||||
|       %b |       %b | ||||||
|         Owner: |         Owner: | ||||||
|     %td |     %td | ||||||
|       = @group.owner_name |       = @group.owner_name | ||||||
| .ui-box |       .right | ||||||
|   %h5 |         = link_to "#", class: "btn btn-small change-owner-link" do | ||||||
|     Projects |           %i.icon-edit | ||||||
|     %small |           Change owner | ||||||
|       (#{@group.projects.count}) | 
 | ||||||
|   %ul.unstyled |   %tr.change-owner-holder.hide | ||||||
|  |     %td.bgred | ||||||
|  |       %b.cred | ||||||
|  |         New Owner: | ||||||
|  |     %td.bgred | ||||||
|  |       = form_for [:admin, @group] do |f| | ||||||
|  |         = f.select :owner_id, User.all.map { |user| [user.name, user.id] }, {}, {class: 'chosen'} | ||||||
|  |         %div | ||||||
|  |           = f.submit 'Change Owner', class: "btn danger" | ||||||
|  |           = link_to "Cancel", "#", class: "btn change-owner-cancel-link" | ||||||
|  | %fieldset | ||||||
|  |   %legend Projects (#{@group.projects.count}) | ||||||
|  |   %table | ||||||
|  |     %thead | ||||||
|  |       %tr | ||||||
|  |         %th Project name | ||||||
|  |         %th Path | ||||||
|  |         %th Users | ||||||
|  |         %th.cred Danger Zone! | ||||||
|     - @group.projects.each do |project| |     - @group.projects.each do |project| | ||||||
|       %li.wll |       %tr | ||||||
|         %strong |         %td | ||||||
|           = link_to project.name, [:admin, project] |           = link_to project.name_with_namespace, [:admin, project] | ||||||
|         .right |         %td | ||||||
|           = link_to 'Remove from group', remove_project_admin_group_path(@group, project_id: project.id), confirm: 'Are you sure?', method: :delete, class: "btn danger small" |           %span.monospace= project.path_with_namespace + ".git" | ||||||
|         .clearfix |         %td= project.users.count | ||||||
|  |         %td.bgred | ||||||
|  |           = link_to 'Transfer project to global namespace', remove_project_admin_group_path(@group, project_id: project.id), confirm: 'Remove project from group and move to global namespace. Are you sure?', method: :delete, class: "btn danger small" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| = form_tag project_update_admin_group_path(@group), class: "bulk_import", method: :put  do | = form_tag project_update_admin_group_path(@group), class: "bulk_import", method: :put  do | ||||||
|   %fieldset |   %fieldset | ||||||
|     %legend Move projects to group |     %legend Move projects to group | ||||||
|  |     .alert | ||||||
|  |       You can move only projects with existing repos | ||||||
|  |       %br | ||||||
|  |       Group projects will be moved in group directory and will not be accessible by old path | ||||||
|     .clearfix |     .clearfix | ||||||
|       = label_tag :project_ids do |       = label_tag :project_ids do | ||||||
|         Projects |         Projects | ||||||
|  | @ -53,3 +78,17 @@ | ||||||
|         = select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' |         = select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' | ||||||
|     .form-actions |     .form-actions | ||||||
|       = submit_tag 'Add', class: "btn primary" |       = submit_tag 'Add', class: "btn primary" | ||||||
|  | 
 | ||||||
|  | :javascript | ||||||
|  |   $(function(){ | ||||||
|  |     var modal = $('.change-owner-holder'); | ||||||
|  |     $('.change-owner-link').bind("click", function(){ | ||||||
|  |       $(this).hide(); | ||||||
|  |       modal.show(); | ||||||
|  |     }); | ||||||
|  |     $('.change-owner-cancel-link').bind("click", function(){ | ||||||
|  |       modal.hide(); | ||||||
|  |       $('.change-owner-link').show(); | ||||||
|  |     }) | ||||||
|  |   }) | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | @ -3,6 +3,8 @@ | ||||||
|     = link_to "githost.log", "#githost", 'data-toggle' => 'tab' |     = link_to "githost.log", "#githost", 'data-toggle' => 'tab' | ||||||
|   %li |   %li | ||||||
|     = link_to "application.log", "#application", 'data-toggle' => 'tab' |     = link_to "application.log", "#application", 'data-toggle' => 'tab' | ||||||
|  |   %li | ||||||
|  |     = link_to "production.log", "#production", 'data-toggle' => 'tab' | ||||||
| 
 | 
 | ||||||
| %p.light To prevent perfomance issues admin logs output the last 2000 lines | %p.light To prevent perfomance issues admin logs output the last 2000 lines | ||||||
| .tab-content | .tab-content | ||||||
|  | @ -34,3 +36,17 @@ | ||||||
|           - Gitlab::AppLogger.read_latest.each do |line| |           - Gitlab::AppLogger.read_latest.each do |line| | ||||||
|             %li |             %li | ||||||
|               %p= line |               %p= line | ||||||
|  |   .tab-pane#production | ||||||
|  |     .file_holder#README | ||||||
|  |       .file_title | ||||||
|  |         %i.icon-file | ||||||
|  |         production.log | ||||||
|  |         .right | ||||||
|  |           = link_to '#', class: 'log-bottom' do | ||||||
|  |             %i.icon-arrow-down | ||||||
|  |             Scroll down | ||||||
|  |       .file_content.logs | ||||||
|  |         %ol | ||||||
|  |           - Gitlab::Logger.read_latest_for('production.log').each do |line| | ||||||
|  |             %li | ||||||
|  |               %p= line | ||||||
|  |  | ||||||
|  | @ -19,40 +19,47 @@ | ||||||
|       .input |       .input | ||||||
|         = text_field_tag :ppath, @project.path_to_repo, class: "xlarge", disabled: true |         = text_field_tag :ppath, @project.path_to_repo, class: "xlarge", disabled: true | ||||||
| 
 | 
 | ||||||
|     - unless project.new_record? |     - if project.repo_exists? | ||||||
|       .clearfix |       .clearfix | ||||||
|         = f.label :namespace_id |         = f.label :default_branch, "Default Branch" | ||||||
|         .input= f.select :namespace_id, namespaces_options(@project.namespace_id), {}, {class: 'chosen'} |         .input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;") | ||||||
| 
 | 
 | ||||||
|       - if project.repo_exists? |   %fieldset.adv_settings | ||||||
|         .clearfix |     %legend Features: | ||||||
|           = f.label :default_branch, "Default Branch" |  | ||||||
|           .input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;") |  | ||||||
| 
 | 
 | ||||||
|   - unless project.new_record? |     .clearfix | ||||||
|     %fieldset.adv_settings |       = f.label :issues_enabled, "Issues" | ||||||
|       %legend Features: |       .input= f.check_box :issues_enabled | ||||||
| 
 | 
 | ||||||
|       .clearfix |     .clearfix | ||||||
|         = f.label :issues_enabled, "Issues" |       = f.label :merge_requests_enabled, "Merge Requests" | ||||||
|         .input= f.check_box :issues_enabled |       .input= f.check_box :merge_requests_enabled | ||||||
| 
 | 
 | ||||||
|       .clearfix |     .clearfix | ||||||
|         = f.label :merge_requests_enabled, "Merge Requests" |       = f.label :wall_enabled, "Wall" | ||||||
|         .input= f.check_box :merge_requests_enabled |       .input= f.check_box :wall_enabled | ||||||
| 
 | 
 | ||||||
|       .clearfix |     .clearfix | ||||||
|         = f.label :wall_enabled, "Wall" |       = f.label :wiki_enabled, "Wiki" | ||||||
|         .input= f.check_box :wall_enabled |       .input= f.check_box :wiki_enabled | ||||||
| 
 | 
 | ||||||
|       .clearfix |   %fieldset.features | ||||||
|         = f.label :wiki_enabled, "Wiki" |     %legend Transfer: | ||||||
|         .input= f.check_box :wiki_enabled |     .control-group | ||||||
|  |       = f.label :namespace_id do | ||||||
|  |         %span Namespace | ||||||
|  |       .controls | ||||||
|  |         = f.select :namespace_id, namespaces_options(@project.namespace_id, :all), {}, {class: 'chosen'} | ||||||
|  |         %br | ||||||
|  |         %ul.prepend-top-10.cred | ||||||
|  |           %li Be careful. Changing project namespace can have unintended side effects | ||||||
|  |           %li You can transfer project only to namespaces you can manage | ||||||
|  |           %li You will need to update your local repositories to point to the new location. | ||||||
| 
 | 
 | ||||||
|   - unless project.new_record? | 
 | ||||||
|     .actions |   .actions | ||||||
|       = f.submit 'Save Project', class: "btn save-btn" |     = f.submit 'Save Project', class: "btn save-btn" | ||||||
|       = link_to 'Cancel', admin_projects_path, class: "btn cancel-btn" |     = link_to 'Cancel', admin_projects_path, class: "btn cancel-btn" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| %h3.page_title | %h3.page_title | ||||||
|   Projects |   Projects (#{@projects.count}) | ||||||
|   = link_to 'New Project', new_project_path, class: "btn small right" |   = link_to 'New Project', new_project_path, class: "btn small right" | ||||||
| %br | %br | ||||||
| = form_tag admin_projects_path, method: :get, class: 'form-inline' do | = form_tag admin_projects_path, method: :get, class: 'form-inline' do | ||||||
|  | @ -9,12 +9,15 @@ | ||||||
| 
 | 
 | ||||||
| %table | %table | ||||||
|   %thead |   %thead | ||||||
|     %th Name |     %tr | ||||||
|     %th Path |       %th | ||||||
|     %th Team Members |         Name | ||||||
|     %th Last Commit |         %i.icon-sort-down | ||||||
|     %th Edit |       %th Path | ||||||
|     %th.cred Danger Zone! |       %th Team Members | ||||||
|  |       %th Last Commit | ||||||
|  |       %th Edit | ||||||
|  |       %th.cred Danger Zone! | ||||||
| 
 | 
 | ||||||
|   - @projects.each do |project| |   - @projects.each do |project| | ||||||
|     %tr |     %tr | ||||||
|  |  | ||||||
|  | @ -4,14 +4,24 @@ | ||||||
|     %i.icon-edit |     %i.icon-edit | ||||||
|     Edit |     Edit | ||||||
| 
 | 
 | ||||||
| - if !@project.has_post_receive_file? && @project.has_commits? | - if @project.has_commits? | ||||||
|   %br |   - if !@project.has_post_receive_file? | ||||||
|   .alert.alert-error |     %br | ||||||
|     %span |     .alert.alert-error | ||||||
|       %strong Important! |       %span | ||||||
|       Project has commits but missing post-receive file. |         %strong Project has commits but missing post-receive file. | ||||||
|       %br |         %br | ||||||
|       If you exported project manually - copy post-receive hook to bare repository |         If you exported project manually - make a link of post-receive hook file from gitolite to project repository | ||||||
|  |   - elsif !@project.valid_post_receive_file? | ||||||
|  |     %br | ||||||
|  |     .alert.alert-error | ||||||
|  |       %span | ||||||
|  |         %strong Project has invalid post-receive file. | ||||||
|  |         %br | ||||||
|  |         1. Make sure your gitolite instace has latest post-receive file. | ||||||
|  |         %br | ||||||
|  |         2. Make a link of post-receive hook file from gitolite to project repository | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| %br | %br | ||||||
| %table.zebra-striped | %table.zebra-striped | ||||||
|  | @ -37,23 +47,63 @@ | ||||||
|   %tr |   %tr | ||||||
|     %td |     %td | ||||||
|       %b |       %b | ||||||
|         Path: |         Owned by: | ||||||
|     %td |     %td | ||||||
|       %code= @project.path_to_repo |       - if @project.chief | ||||||
|  |         = link_to @project.chief.name, admin_user_path(@project.chief) | ||||||
|  |       - else | ||||||
|  |         (deleted) | ||||||
|   %tr |   %tr | ||||||
|     %td |     %td | ||||||
|       %b |       %b | ||||||
|         Created by: |         Created by: | ||||||
|     %td |     %td | ||||||
|       = @project.owner_name || '(deleted)' |       = @project.owner_name || '(deleted)' | ||||||
|  |   %tr | ||||||
|  |     %td | ||||||
|  |       %b | ||||||
|  |         Created at: | ||||||
|  |     %td | ||||||
|  |       = @project.created_at.stamp("March 1, 1999") | ||||||
|  | 
 | ||||||
|  | %table.zebra-striped | ||||||
|  |   %thead | ||||||
|  |     %tr | ||||||
|  |       %th Repository | ||||||
|  |       %th | ||||||
|  |   %tr | ||||||
|  |     %td | ||||||
|  |       %b | ||||||
|  |         FS Path: | ||||||
|  |     %td | ||||||
|  |       %code= @project.path_to_repo | ||||||
|  |   %tr | ||||||
|  |     %td | ||||||
|  |       %b | ||||||
|  |         Smart HTTP: | ||||||
|  |     %td | ||||||
|  |       = link_to @project.http_url_to_repo | ||||||
|  |   %tr | ||||||
|  |     %td | ||||||
|  |       %b | ||||||
|  |         SSH: | ||||||
|  |     %td | ||||||
|  |       = link_to @project.ssh_url_to_repo | ||||||
|  |   %tr | ||||||
|  |     %td | ||||||
|  |       %b | ||||||
|  |         Last commit at: | ||||||
|  |     %td | ||||||
|  |       = last_commit(@project) | ||||||
|   %tr |   %tr | ||||||
|     %td |     %td | ||||||
|       %b |       %b | ||||||
|         Post Receive File: |         Post Receive File: | ||||||
|     %td |     %td | ||||||
|       = check_box_tag :post_receive_file, 1, @project.has_post_receive_file?, disabled: true |       = check_box_tag :post_receive_file, 1, @project.has_post_receive_file?, disabled: true | ||||||
|  | 
 | ||||||
| %br | %br | ||||||
| %h3 | %h5 | ||||||
|   Team |   Team | ||||||
|   %small |   %small | ||||||
|     (#{@project.users_projects.count}) |     (#{@project.users_projects.count}) | ||||||
|  | @ -75,7 +125,7 @@ | ||||||
|       %td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn danger small" |       %td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn danger small" | ||||||
| 
 | 
 | ||||||
| %br | %br | ||||||
| %h3 Add new team member | %h5 Add new team member | ||||||
| %br | %br | ||||||
| = form_tag team_update_admin_project_path(@project), class: "bulk_import", method: :put  do | = form_tag team_update_admin_project_path(@project), class: "bulk_import", method: :put  do | ||||||
|   %table.zebra-striped |   %table.zebra-striped | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| %h3.page_title | %h3.page_title | ||||||
|   Users |   Users (#{@admin_users.count}) | ||||||
|   = link_to 'New User', new_admin_user_path, class: "btn small right" |   = link_to 'New User', new_admin_user_path, class: "btn small right" | ||||||
| %br | %br | ||||||
| 
 | 
 | ||||||
|  | @ -21,13 +21,16 @@ | ||||||
| 
 | 
 | ||||||
| %table | %table | ||||||
|   %thead |   %thead | ||||||
|     %th Admin |     %tr | ||||||
|     %th Name |       %th Admin | ||||||
|     %th Username |       %th | ||||||
|     %th Email |         Name | ||||||
|     %th Projects |         %i.icon-sort-down | ||||||
|     %th Edit |       %th Username | ||||||
|     %th.cred Danger Zone! |       %th Email | ||||||
|  |       %th Projects | ||||||
|  |       %th Edit | ||||||
|  |       %th.cred Danger Zone! | ||||||
| 
 | 
 | ||||||
|   - @admin_users.each do |user| |   - @admin_users.each do |user| | ||||||
|     %tr |     %tr | ||||||
|  | @ -38,10 +41,13 @@ | ||||||
|       %td= user.users_projects.count |       %td= user.users_projects.count | ||||||
|       %td= link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn small" |       %td= link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn small" | ||||||
|       %td.bgred |       %td.bgred | ||||||
|         - if user.blocked |         - if user == current_user | ||||||
|           = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn small success" |           %span.cred It's you! | ||||||
|         - else |         - else | ||||||
|           = link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small danger" |           - if user.blocked | ||||||
|         = link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn small danger" |             = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn small success" | ||||||
|  |           - else | ||||||
|  |             = link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small danger" | ||||||
|  |           = link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn small danger" | ||||||
| 
 | 
 | ||||||
| = paginate @admin_users, theme: "admin" | = paginate @admin_users, theme: "admin" | ||||||
|  |  | ||||||
|  | @ -37,6 +37,12 @@ | ||||||
|       %b |       %b | ||||||
|         Blocked: |         Blocked: | ||||||
|         %td= check_box_tag "blocked", 1, @admin_user.blocked, disabled: :disabled |         %td= check_box_tag "blocked", 1, @admin_user.blocked, disabled: :disabled | ||||||
|  |   %tr | ||||||
|  |     %td | ||||||
|  |       %b | ||||||
|  |         Created at: | ||||||
|  |     %td | ||||||
|  |       = @admin_user.created_at.stamp("March 1, 1999") | ||||||
|   %tr |   %tr | ||||||
|     %td |     %td | ||||||
|       %b |       %b | ||||||
|  | @ -66,7 +72,7 @@ | ||||||
|         = @admin_user.twitter |         = @admin_user.twitter | ||||||
| 
 | 
 | ||||||
| %br | %br | ||||||
| %h3 Add User to Projects | %h5 Add User to Projects | ||||||
| %br | %br | ||||||
| = form_tag team_update_admin_user_path(@admin_user), class: "bulk_import", method: :put  do | = form_tag team_update_admin_user_path(@admin_user), class: "bulk_import", method: :put  do | ||||||
|   %table |   %table | ||||||
|  | @ -76,7 +82,7 @@ | ||||||
|         %th Project Access: |         %th Project Access: | ||||||
| 
 | 
 | ||||||
|     %tr |     %tr | ||||||
|       %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name),  multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' |       %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace),  multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' | ||||||
|       %td= select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select chosen span3" |       %td= select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select chosen span3" | ||||||
| 
 | 
 | ||||||
|     %tr |     %tr | ||||||
|  | @ -86,8 +92,22 @@ | ||||||
|         %strong= link_to "here", help_permissions_path, class: "vlink" |         %strong= link_to "here", help_permissions_path, class: "vlink" | ||||||
| %br | %br | ||||||
| 
 | 
 | ||||||
|  | - if @admin_user.groups.present? | ||||||
|  |   %h5 Owner of groups: | ||||||
|  |   %br | ||||||
|  | 
 | ||||||
|  |   %table.zebra-striped | ||||||
|  |     %thead | ||||||
|  |       %tr | ||||||
|  |         %th Name | ||||||
|  | 
 | ||||||
|  |     - @admin_user.groups.each do |group| | ||||||
|  |       %tr | ||||||
|  |         %td= link_to group.name, admin_group_path(group) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| - if @admin_user.projects.present? | - if @admin_user.projects.present? | ||||||
|   %h3 Projects |   %h5 Projects: | ||||||
|   %br |   %br | ||||||
| 
 | 
 | ||||||
|   %table.zebra-striped |   %table.zebra-striped | ||||||
|  | @ -101,7 +121,7 @@ | ||||||
|     - @admin_user.users_projects.each do |tm| |     - @admin_user.users_projects.each do |tm| | ||||||
|       - project = tm.project |       - project = tm.project | ||||||
|       %tr |       %tr | ||||||
|         %td= link_to project.name, admin_project_path(project) |         %td= link_to project.name_with_namespace, admin_project_path(project) | ||||||
|         %td= tm.project_access_human |         %td= tm.project_access_human | ||||||
|         %td= link_to 'Edit Access', edit_admin_team_member_path(tm), class: "btn small" |         %td= link_to 'Edit Access', edit_admin_team_member_path(tm), class: "btn small" | ||||||
|         %td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn small danger" |         %td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn small danger" | ||||||
|  |  | ||||||
|  | @ -3,4 +3,4 @@ | ||||||
|     %h5.small |     %h5.small | ||||||
|       %i.icon-calendar |       %i.icon-calendar | ||||||
|       = day.stamp("28 Aug, 2010") |       = day.stamp("28 Aug, 2010") | ||||||
|     %ul.unstyled= render commits |     %ul.well-list= render commits | ||||||
|  |  | ||||||
|  | @ -1,23 +1,30 @@ | ||||||
| %div | %div | ||||||
|   %p.slead |   - unless params[:to] | ||||||
|     Fill input field with commit id like |     %p.slead | ||||||
|     %code.label_branch 4eedf23 |       Fill input field with commit id like | ||||||
|     or branch/tag name like |       %code.label_branch 4eedf23 | ||||||
|     %code.label_branch master |       or branch/tag name like | ||||||
|     and press compare button for commits list, code diff. |       %code.label_branch master | ||||||
|  |       and press compare button for commits list, code diff. | ||||||
| 
 | 
 | ||||||
|   %br |     %br | ||||||
| 
 | 
 | ||||||
|   = form_tag project_compare_index_path(@project), method: :post do |   = form_tag project_compare_index_path(@project), method: :post do | ||||||
|     .clearfix |     .clearfix | ||||||
|       = text_field_tag :from, params[:from], placeholder: "master", class: "xlarge" |       .pull-left | ||||||
|       = "..." |         - if params[:to] && params[:from] | ||||||
|       = text_field_tag :to, params[:to], placeholder: "aa8b4ef", class: "xlarge" |           = link_to 'switch', {from: params[:to], to: params[:from]}, {class: 'commits-compare-switch has_tooltip', title: 'Switch base of comparison'} | ||||||
|  |         = text_field_tag :from, params[:from], placeholder: "master", class: "xlarge" | ||||||
|  |         = "..." | ||||||
|  |         = text_field_tag :to, params[:to], placeholder: "aa8b4ef", class: "xlarge" | ||||||
|  |       .pull-left | ||||||
|  |           | ||||||
|  |         = submit_tag "Compare", class: "btn primary wide commits-compare-btn" | ||||||
|     - if @refs_are_same |     - if @refs_are_same | ||||||
|       .alert |       .alert | ||||||
|         %span Refs are the same |         %span Refs are the same | ||||||
|     .actions | 
 | ||||||
|       = submit_tag "Compare", class: "btn primary wide commits-compare-btn" | 
 | ||||||
| 
 | 
 | ||||||
| :javascript | :javascript | ||||||
|   $(function() { |   $(function() { | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ | ||||||
| - if @commits.present? | - if @commits.present? | ||||||
|   %div.ui-box |   %div.ui-box | ||||||
|     %h5.small Commits (#{@commits.count}) |     %h5.small Commits (#{@commits.count}) | ||||||
|     %ul.unstyled= render @commits |     %ul.well-list= render @commits | ||||||
| 
 | 
 | ||||||
|   - unless @diffs.empty? |   - unless @diffs.empty? | ||||||
|     %h4 Diff |     %h4 Diff | ||||||
|  |  | ||||||