Commit db2c15369c365340aeaf4e431e8838714b40396b
Exists in
master
and in
4 other branches
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
Showing
280 changed files
with
4590 additions
and
2727 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 280 files displayed.
.travis.yml
| 1 | env: | 1 | env: |
| 2 | + - DB=postgresql | ||
| 2 | - DB=mysql | 3 | - DB=mysql |
| 3 | before_install: | 4 | before_install: |
| 4 | - sudo apt-get install libicu-dev -y | 5 | - sudo apt-get install libicu-dev -y |
| @@ -18,8 +19,7 @@ services: | @@ -18,8 +19,7 @@ services: | ||
| 18 | before_script: | 19 | before_script: |
| 19 | - "cp config/database.yml.$DB config/database.yml" | 20 | - "cp config/database.yml.$DB config/database.yml" |
| 20 | - "cp config/gitlab.yml.example config/gitlab.yml" | 21 | - "cp config/gitlab.yml.example config/gitlab.yml" |
| 21 | - - "bundle exec rake db:create RAILS_ENV=test" | ||
| 22 | - - "bundle exec rake db:migrate RAILS_ENV=test" | 22 | + - "bundle exec rake db:setup RAILS_ENV=test" |
| 23 | - "bundle exec rake db:seed_fu RAILS_ENV=test" | 23 | - "bundle exec rake db:seed_fu RAILS_ENV=test" |
| 24 | - "sh -e /etc/init.d/xvfb start" | 24 | - "sh -e /etc/init.d/xvfb start" |
| 25 | script: "bundle exec rake travis --trace" | 25 | script: "bundle exec rake travis --trace" |
CHANGELOG
| 1 | v 4.0.0 | 1 | v 4.0.0 |
| 2 | + - Reorganized settings | ||
| 3 | + - Fixed commits compare | ||
| 4 | + - Refactored scss | ||
| 5 | + - Improve status checks | ||
| 6 | + - Validates presence of User#name | ||
| 7 | + - Fixed postgres support | ||
| 8 | + - Removed sqlite support | ||
| 9 | + - Modified post-receive hook | ||
| 10 | + - Milestones can be closed now | ||
| 11 | + - Show comment events on dashboard | ||
| 12 | + - Quick add team members via group#people page | ||
| 2 | - [API] expose created date for hooks and SSH keys | 13 | - [API] expose created date for hooks and SSH keys |
| 3 | - [API] list, create issue notes | 14 | - [API] list, create issue notes |
| 4 | - [API] list, create snippet notes | 15 | - [API] list, create snippet notes |
CONTRIBUTING.md
| 1 | -## Contribute to GitLab | 1 | +# Contact & support |
| 2 | 2 | ||
| 3 | -If you want to contribute to GitLab, follow this process: | 3 | +If you want quick help, head over to our [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq). |
| 4 | +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. | ||
| 4 | 5 | ||
| 5 | -1. Fork the project | ||
| 6 | -2. Create a feature branch | ||
| 7 | -3. Code | ||
| 8 | -4. Create a pull request | ||
| 9 | 6 | ||
| 10 | -We will only accept pull requests if: | ||
| 11 | 7 | ||
| 12 | -* Your code has proper tests and all tests pass | ||
| 13 | -* Your code can be merged w/o problems | ||
| 14 | -* It won't break existing functionality | ||
| 15 | -* It's quality code | ||
| 16 | -* We like it :) | 8 | +# Contribute to GitLab |
| 17 | 9 | ||
| 18 | -For examples of feedback on pull requests please look at the [closed pull requests](https://github.com/gitlabhq/gitlabhq/pulls?direction=desc&page=1&sort=created&state=closed). | 10 | +## Recipes |
| 19 | 11 | ||
| 20 | -## Installation | 12 | +We collect user submitted installation scripts and config file templates for platforms we don't support officially. |
| 13 | +We believe there is merit in allowing a certain amount of diversity. | ||
| 14 | +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. | ||
| 21 | 15 | ||
| 22 | -Install the Gitlab development in a virtual machine with the [Gitlab Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm). Installing it in a virtual machine makes it much easier to set up all the dependencies for integration testing. | 16 | +Help us improve the collection of [GitLab Recipes](https://github.com/gitlabhq/gitlab-recipes/) |
| 23 | 17 | ||
| 24 | -## Running tests | ||
| 25 | 18 | ||
| 26 | -For more information on running the tests please read the [development tips](https://github.com/gitlabhq/gitlabhq/blob/master/doc/development.md) | 19 | +## Feature suggestions |
| 20 | + | ||
| 21 | +Follow the [Issue Submission Guide](https://github.com/gitlabhq/gitlabhq/wiki/Issue-Submission-Guide) and support other peoples ideas or propose your own. | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +## Code | ||
| 25 | + | ||
| 26 | +Follow our [Developer Guide](https://github.com/gitlabhq/gitlabhq/wiki/Developer-Guide) to set you up for hacking on GitLab. |
Gemfile
| @@ -32,7 +32,7 @@ gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: | @@ -32,7 +32,7 @@ gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: | ||
| 32 | gem "gitolite", '1.1.0' | 32 | gem "gitolite", '1.1.0' |
| 33 | 33 | ||
| 34 | # Syntax highlighter | 34 | # Syntax highlighter |
| 35 | -gem "pygments.rb", git: "https://github.com/gitlabhq/pygments.rb.git", ref: '4db80c599067e2d5f23c5c243bf85b8ca0368ad4' | 35 | +gem "pygments.rb", git: "https://github.com/gitlabhq/pygments.rb.git", branch: "master" |
| 36 | 36 | ||
| 37 | # Language detection | 37 | # Language detection |
| 38 | gem "github-linguist", "~> 2.3.4" , require: "linguist" | 38 | gem "github-linguist", "~> 2.3.4" , require: "linguist" |
| @@ -100,7 +100,7 @@ group :assets do | @@ -100,7 +100,7 @@ group :assets do | ||
| 100 | gem "therubyracer" | 100 | gem "therubyracer" |
| 101 | 101 | ||
| 102 | gem 'chosen-rails', "0.9.8" | 102 | gem 'chosen-rails', "0.9.8" |
| 103 | - gem 'jquery-atwho-rails', "0.1.6" | 103 | + gem 'jquery-atwho-rails', "0.1.7" |
| 104 | gem "jquery-rails", "2.1.3" | 104 | gem "jquery-rails", "2.1.3" |
| 105 | gem "jquery-ui-rails", "2.0.2" | 105 | gem "jquery-ui-rails", "2.0.2" |
| 106 | gem "modernizr", "2.6.2" | 106 | gem "modernizr", "2.6.2" |
| @@ -124,7 +124,7 @@ group :development, :test do | @@ -124,7 +124,7 @@ group :development, :test do | ||
| 124 | gem "capybara" | 124 | gem "capybara" |
| 125 | gem "pry" | 125 | gem "pry" |
| 126 | gem "awesome_print" | 126 | gem "awesome_print" |
| 127 | - gem "database_cleaner" | 127 | + gem "database_cleaner", ref: "f89c34300e114be99532f14c115b2799a3380ac6", git: "https://github.com/bmabey/database_cleaner.git" |
| 128 | gem "launchy" | 128 | gem "launchy" |
| 129 | gem 'factory_girl_rails' | 129 | gem 'factory_girl_rails' |
| 130 | 130 |
Gemfile.lock
| 1 | GIT | 1 | GIT |
| 2 | + remote: https://github.com/bmabey/database_cleaner.git | ||
| 3 | + revision: f89c34300e114be99532f14c115b2799a3380ac6 | ||
| 4 | + ref: f89c34300e114be99532f14c115b2799a3380ac6 | ||
| 5 | + specs: | ||
| 6 | + database_cleaner (0.9.1) | ||
| 7 | + | ||
| 8 | +GIT | ||
| 2 | remote: https://github.com/ctran/annotate_models.git | 9 | remote: https://github.com/ctran/annotate_models.git |
| 3 | revision: be4e26825b521f0b2d86b181e2dff89901aa9b1e | 10 | revision: be4e26825b521f0b2d86b181e2dff89901aa9b1e |
| 4 | specs: | 11 | specs: |
| @@ -45,8 +52,8 @@ GIT | @@ -45,8 +52,8 @@ GIT | ||
| 45 | 52 | ||
| 46 | GIT | 53 | GIT |
| 47 | remote: https://github.com/gitlabhq/pygments.rb.git | 54 | remote: https://github.com/gitlabhq/pygments.rb.git |
| 48 | - revision: 4db80c599067e2d5f23c5c243bf85b8ca0368ad4 | ||
| 49 | - ref: 4db80c599067e2d5f23c5c243bf85b8ca0368ad4 | 55 | + revision: db1da0343adf86b49bdc3add04d02d2e80438d38 |
| 56 | + branch: master | ||
| 50 | specs: | 57 | specs: |
| 51 | pygments.rb (0.3.2) | 58 | pygments.rb (0.3.2) |
| 52 | posix-spawn (~> 0.3.6) | 59 | posix-spawn (~> 0.3.6) |
| @@ -140,7 +147,6 @@ GEM | @@ -140,7 +147,6 @@ GEM | ||
| 140 | colorize (0.5.8) | 147 | colorize (0.5.8) |
| 141 | crack (0.3.1) | 148 | crack (0.3.1) |
| 142 | daemons (1.1.9) | 149 | daemons (1.1.9) |
| 143 | - database_cleaner (0.9.1) | ||
| 144 | devise (2.1.2) | 150 | devise (2.1.2) |
| 145 | bcrypt-ruby (~> 3.0) | 151 | bcrypt-ruby (~> 3.0) |
| 146 | orm_adapter (~> 0.1) | 152 | orm_adapter (~> 0.1) |
| @@ -227,7 +233,7 @@ GEM | @@ -227,7 +233,7 @@ GEM | ||
| 227 | httpauth (0.2.0) | 233 | httpauth (0.2.0) |
| 228 | i18n (0.6.1) | 234 | i18n (0.6.1) |
| 229 | journey (1.0.4) | 235 | journey (1.0.4) |
| 230 | - jquery-atwho-rails (0.1.6) | 236 | + jquery-atwho-rails (0.1.7) |
| 231 | jquery-rails (2.1.3) | 237 | jquery-rails (2.1.3) |
| 232 | railties (>= 3.1.0, < 5.0) | 238 | railties (>= 3.1.0, < 5.0) |
| 233 | thor (~> 0.14) | 239 | thor (~> 0.14) |
| @@ -458,7 +464,7 @@ DEPENDENCIES | @@ -458,7 +464,7 @@ DEPENDENCIES | ||
| 458 | chosen-rails (= 0.9.8) | 464 | chosen-rails (= 0.9.8) |
| 459 | coffee-rails (~> 3.2.2) | 465 | coffee-rails (~> 3.2.2) |
| 460 | colored | 466 | colored |
| 461 | - database_cleaner | 467 | + database_cleaner! |
| 462 | devise (~> 2.1.0) | 468 | devise (~> 2.1.0) |
| 463 | draper (~> 0.18.0) | 469 | draper (~> 0.18.0) |
| 464 | email_spec | 470 | email_spec |
| @@ -481,7 +487,7 @@ DEPENDENCIES | @@ -481,7 +487,7 @@ DEPENDENCIES | ||
| 481 | guard-spinach | 487 | guard-spinach |
| 482 | haml-rails (~> 0.3.5) | 488 | haml-rails (~> 0.3.5) |
| 483 | httparty | 489 | httparty |
| 484 | - jquery-atwho-rails (= 0.1.6) | 490 | + jquery-atwho-rails (= 0.1.7) |
| 485 | jquery-rails (= 2.1.3) | 491 | jquery-rails (= 2.1.3) |
| 486 | jquery-ui-rails (= 2.0.2) | 492 | jquery-ui-rails (= 2.0.2) |
| 487 | kaminari (~> 0.14.1) | 493 | kaminari (~> 0.14.1) |
README.md
| 1 | -# Welcome to GitLab [](https://secure.travis-ci.org/gitlabhq/gitlabhq) [](https://secure.travis-ci.org/gitlabhq/grit) [](https://codeclimate.com/github/gitlabhq/gitlabhq) | 1 | +# 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) |
| 2 | 2 | ||
| 3 | GitLab is a free project and repository management application | 3 | GitLab is a free project and repository management application |
| 4 | 4 |
VERSION
app/assets/fonts/korolev-medium-compressed.otf
No preview for this file type
8.17 KB
app/assets/images/logo.png
2.93 KB
app/assets/images/logo_basic.png
3.2 KB
app/assets/images/logo_text.png
4.49 KB
app/assets/images/logo_text_tr.png
3.21 KB
app/assets/images/logo_white.png
app/assets/images/service-disabled-gitlab-ci.png
2.13 KB
app/assets/images/service-gitlab-ci.png
2.34 KB
1.17 KB
app/assets/javascripts/gfm_auto_complete.js.coffee
| 1 | # Creates the variables for setting up GFM auto-completion | 1 | # Creates the variables for setting up GFM auto-completion |
| 2 | 2 | ||
| 3 | window.GitLab ?= {} | 3 | window.GitLab ?= {} |
| 4 | -GitLab.GfmAutoComplete ?= {} | ||
| 5 | - | ||
| 6 | -# Emoji | ||
| 7 | -data = [] | ||
| 8 | -template = "<li data-value='${insert}'>${name} <img alt='${name}' height='20' src='${image}' width='20' /></li>" | ||
| 9 | -GitLab.GfmAutoComplete.Emoji = {data, template} | ||
| 10 | - | ||
| 11 | -# Team Members | ||
| 12 | -data = [] | ||
| 13 | -url = ''; | ||
| 14 | -params = {private_token: '', page: 1} | ||
| 15 | -GitLab.GfmAutoComplete.Members = {data, url, params} | ||
| 16 | - | ||
| 17 | -# Add GFM auto-completion to all input fields, that accept GFM input. | ||
| 18 | -GitLab.GfmAutoComplete.setup = -> | ||
| 19 | - input = $('.js-gfm-input') | ||
| 20 | - | 4 | +GitLab.GfmAutoComplete = |
| 21 | # Emoji | 5 | # Emoji |
| 22 | - input.atWho ':', | ||
| 23 | - data: GitLab.GfmAutoComplete.Emoji.data, | ||
| 24 | - tpl: GitLab.GfmAutoComplete.Emoji.template | 6 | + Emoji: |
| 7 | + data: [] | ||
| 8 | + template: '<li data-value="${insert}">${name} <img alt="${name}" height="20" src="${image}" width="20" /></li>' | ||
| 25 | 9 | ||
| 26 | # Team Members | 10 | # Team Members |
| 27 | - input.atWho '@', (query, callback) -> | ||
| 28 | - (getMoreMembers = -> | ||
| 29 | - $.getJSON(GitLab.GfmAutoComplete.Members.url, GitLab.GfmAutoComplete.Members.params) | ||
| 30 | - .success (members) -> | ||
| 31 | - # pick the data we need | ||
| 32 | - newMembersData = $.map(members, (m) -> m.name ) | ||
| 33 | - | ||
| 34 | - # add the new page of data to the rest | ||
| 35 | - $.merge(GitLab.GfmAutoComplete.Members.data, newMembersData) | ||
| 36 | - | ||
| 37 | - # show the pop-up with a copy of the current data | ||
| 38 | - callback(GitLab.GfmAutoComplete.Members.data[..]) | ||
| 39 | - | ||
| 40 | - # are we past the last page? | ||
| 41 | - if newMembersData.length is 0 | ||
| 42 | - # set static data and stop callbacks | ||
| 43 | - input.atWho '@', | ||
| 44 | - data: GitLab.GfmAutoComplete.Members.data | ||
| 45 | - callback: null | ||
| 46 | - else | ||
| 47 | - # get next page | ||
| 48 | - getMoreMembers() | 11 | + Members: |
| 12 | + data: [] | ||
| 13 | + url: '' | ||
| 14 | + params: | ||
| 15 | + private_token: '' | ||
| 16 | + template: '<li data-value="${username}">${username} <small>${name}</small></li>' | ||
| 17 | + | ||
| 18 | + # Add GFM auto-completion to all input fields, that accept GFM input. | ||
| 19 | + setup: -> | ||
| 20 | + input = $('.js-gfm-input') | ||
| 21 | + | ||
| 22 | + # Emoji | ||
| 23 | + input.atWho ':', | ||
| 24 | + data: @Emoji.data | ||
| 25 | + tpl: @Emoji.template | ||
| 26 | + | ||
| 27 | + # Team Members | ||
| 28 | + input.atWho '@', | ||
| 29 | + tpl: @Members.template | ||
| 30 | + callback: (query, callback) => | ||
| 31 | + request_params = $.extend({}, @Members.params, query: query) | ||
| 32 | + $.getJSON(@Members.url, request_params).done (members) => | ||
| 33 | + new_members_data = $.map(members, (m) -> | ||
| 34 | + username: m.username, | ||
| 35 | + name: m.name | ||
| 36 | + ) | ||
| 37 | + callback(new_members_data) | ||
| 49 | 38 | ||
| 50 | - # so the next request gets the next page | ||
| 51 | - GitLab.GfmAutoComplete.Members.params.page += 1 | ||
| 52 | - ).call() |
app/assets/javascripts/issues.js
| 1 | -function switchToNewIssue(){ | ||
| 2 | - $(".issues_content").hide("fade", { direction: "left" }, 150, function(){ | ||
| 3 | - $('select#issue_assignee_id').chosen(); | ||
| 4 | - $('select#issue_milestone_id').chosen(); | ||
| 5 | - $("#new_issue_dialog").show("fade", { direction: "right" }, 150); | ||
| 6 | - $('.top-tabs .add_new').hide(); | ||
| 7 | - disableButtonIfEmptyField("#issue_title", ".save-btn"); | ||
| 8 | - GitLab.GfmAutoComplete.setup(); | ||
| 9 | - }); | ||
| 10 | -} | ||
| 11 | - | ||
| 12 | -function switchToEditIssue(){ | ||
| 13 | - $(".issues_content").hide("fade", { direction: "left" }, 150, function(){ | ||
| 14 | - $('select#issue_assignee_id').chosen(); | ||
| 15 | - $('select#issue_milestone_id').chosen(); | ||
| 16 | - $("#edit_issue_dialog").show("fade", { direction: "right" }, 150); | ||
| 17 | - $('.add_new').hide(); | ||
| 18 | - disableButtonIfEmptyField("#issue_title", ".save-btn"); | ||
| 19 | - GitLab.GfmAutoComplete.setup(); | ||
| 20 | - }); | ||
| 21 | -} | ||
| 22 | - | ||
| 23 | -function switchFromNewIssue(){ | ||
| 24 | - backToIssues(); | ||
| 25 | -} | ||
| 26 | - | ||
| 27 | -function switchFromEditIssue(){ | ||
| 28 | - backToIssues(); | ||
| 29 | -} | ||
| 30 | - | ||
| 31 | -function backToIssues(){ | ||
| 32 | - $("#edit_issue_dialog, #new_issue_dialog").hide("fade", { direction: "right" }, 150, function(){ | ||
| 33 | - $(".issues_content").show("fade", { direction: "left" }, 150, function() { | ||
| 34 | - $("#edit_issue_dialog").html(""); | ||
| 35 | - $("#new_issue_dialog").html(""); | ||
| 36 | - $('.add_new').show(); | ||
| 37 | - }); | ||
| 38 | - }); | ||
| 39 | -} | ||
| 40 | - | ||
| 41 | function initIssuesSearch() { | 1 | function initIssuesSearch() { |
| 42 | var href = $('#issue_search_form').attr('action'); | 2 | var href = $('#issue_search_form').attr('action'); |
| 43 | var last_terms = ''; | 3 | var last_terms = ''; |
| @@ -76,23 +36,15 @@ function issuesPage(){ | @@ -76,23 +36,15 @@ function issuesPage(){ | ||
| 76 | $(this).closest("form").submit(); | 36 | $(this).closest("form").submit(); |
| 77 | }); | 37 | }); |
| 78 | 38 | ||
| 79 | - $("#new_issue_link").click(function(){ | ||
| 80 | - updateNewIssueURL(); | ||
| 81 | - }); | ||
| 82 | - | ||
| 83 | - $('body').on('ajax:success', '.close_issue, .reopen_issue, #new_issue', function(){ | 39 | + $('body').on('ajax:success', '.close_issue, .reopen_issue', function(){ |
| 84 | var t = $(this), | 40 | var t = $(this), |
| 85 | totalIssues, | 41 | totalIssues, |
| 86 | - reopen = t.hasClass('reopen_issue'), | ||
| 87 | - newIssue = false; | ||
| 88 | - if( this.id == 'new_issue' ){ | ||
| 89 | - newIssue = true; | ||
| 90 | - } | ||
| 91 | - $('.issue_counter, #new_issue').each(function(){ | 42 | + reopen = t.hasClass('reopen_issue'); |
| 43 | + $('.issue_counter').each(function(){ | ||
| 92 | var issue = $(this); | 44 | var issue = $(this); |
| 93 | totalIssues = parseInt( $(this).html(), 10 ); | 45 | totalIssues = parseInt( $(this).html(), 10 ); |
| 94 | 46 | ||
| 95 | - if( newIssue || ( reopen && issue.closest('.main_menu').length ) ){ | 47 | + if( reopen && issue.closest('.main_menu').length ){ |
| 96 | $(this).html( totalIssues+1 ); | 48 | $(this).html( totalIssues+1 ); |
| 97 | }else { | 49 | }else { |
| 98 | $(this).html( totalIssues-1 ); | 50 | $(this).html( totalIssues-1 ); |
| @@ -126,20 +78,3 @@ function issuesCheckChanged() { | @@ -126,20 +78,3 @@ function issuesCheckChanged() { | ||
| 126 | $('.issues_filters').show(); | 78 | $('.issues_filters').show(); |
| 127 | } | 79 | } |
| 128 | } | 80 | } |
| 129 | - | ||
| 130 | -function updateNewIssueURL(){ | ||
| 131 | - var new_issue_link = $("#new_issue_link"); | ||
| 132 | - var milestone_id = $("#milestone_id").val(); | ||
| 133 | - var assignee_id = $("#assignee_id").val(); | ||
| 134 | - var new_href = ""; | ||
| 135 | - if(milestone_id){ | ||
| 136 | - new_href = "issue[milestone_id]=" + milestone_id + "&"; | ||
| 137 | - } | ||
| 138 | - if(assignee_id){ | ||
| 139 | - new_href = new_href + "issue[assignee_id]=" + assignee_id; | ||
| 140 | - } | ||
| 141 | - if(new_href.length){ | ||
| 142 | - new_href = new_issue_link.attr("href") + "?" + new_href; | ||
| 143 | - new_issue_link.attr("href", new_href); | ||
| 144 | - } | ||
| 145 | -}; |
app/assets/javascripts/main.js.coffee
| @@ -7,6 +7,18 @@ window.slugify = (text) -> | @@ -7,6 +7,18 @@ window.slugify = (text) -> | ||
| 7 | window.ajaxGet = (url) -> | 7 | window.ajaxGet = (url) -> |
| 8 | $.ajax({type: "GET", url: url, dataType: "script"}) | 8 | $.ajax({type: "GET", url: url, dataType: "script"}) |
| 9 | 9 | ||
| 10 | +window.errorMessage = (message) -> | ||
| 11 | + ehtml = $("<p>") | ||
| 12 | + ehtml.addClass("error_message") | ||
| 13 | + ehtml.html(message) | ||
| 14 | + ehtml | ||
| 15 | + | ||
| 16 | +window.split = (val) -> | ||
| 17 | + return val.split( /,\s*/ ) | ||
| 18 | + | ||
| 19 | +window.extractLast = (term) -> | ||
| 20 | + return split( term ).pop() | ||
| 21 | + | ||
| 10 | # Disable button if text field is empty | 22 | # Disable button if text field is empty |
| 11 | window.disableButtonIfEmptyField = (field_selector, button_selector) -> | 23 | window.disableButtonIfEmptyField = (field_selector, button_selector) -> |
| 12 | field = $(field_selector) | 24 | field = $(field_selector) |
app/assets/javascripts/merge_requests.js
| @@ -26,6 +26,12 @@ var MergeRequest = { | @@ -26,6 +26,12 @@ var MergeRequest = { | ||
| 26 | self.showState(data.state); | 26 | self.showState(data.state); |
| 27 | }, "json"); | 27 | }, "json"); |
| 28 | } | 28 | } |
| 29 | + | ||
| 30 | + if(self.opts.ci_enable){ | ||
| 31 | + $.get(self.opts.url_to_ci_check, function(data){ | ||
| 32 | + self.showCiState(data.status); | ||
| 33 | + }, "json"); | ||
| 34 | + } | ||
| 29 | }, | 35 | }, |
| 30 | 36 | ||
| 31 | initTabs: | 37 | initTabs: |
| @@ -79,6 +85,11 @@ var MergeRequest = { | @@ -79,6 +85,11 @@ var MergeRequest = { | ||
| 79 | $(".automerge_widget." + state).show(); | 85 | $(".automerge_widget." + state).show(); |
| 80 | }, | 86 | }, |
| 81 | 87 | ||
| 88 | + showCiState: | ||
| 89 | + function(state){ | ||
| 90 | + $(".ci_widget").hide(); | ||
| 91 | + $(".ci_widget.ci-" + state).show(); | ||
| 92 | + }, | ||
| 82 | 93 | ||
| 83 | loadDiff: | 94 | loadDiff: |
| 84 | function() { | 95 | function() { |
app/assets/javascripts/projects.js.coffee
| @@ -18,10 +18,3 @@ $ -> | @@ -18,10 +18,3 @@ $ -> | ||
| 18 | # Ref switcher | 18 | # Ref switcher |
| 19 | $('.project-refs-select').on 'change', -> | 19 | $('.project-refs-select').on 'change', -> |
| 20 | $(@).parents('form').submit() | 20 | $(@).parents('form').submit() |
| 21 | - | ||
| 22 | -class @GraphNav | ||
| 23 | - @init: -> | ||
| 24 | - $('.graph svg').css 'position', 'relative' | ||
| 25 | - $('body').bind 'keyup', (e) -> | ||
| 26 | - $('.graph svg').animate(left: '+=400') if e.keyCode is 37 # left | ||
| 27 | - $('.graph svg').animate(left: '-=400') if e.keyCode is 39 # right |
app/assets/stylesheets/application.css
| @@ -1,10 +0,0 @@ | @@ -1,10 +0,0 @@ | ||
| 1 | -/* | ||
| 2 | - * This is a manifest file that'll automatically include all the stylesheets available in this directory | ||
| 3 | - * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at | ||
| 4 | - * the top of the compiled file, but it's generally better to create a new file per style scope. | ||
| 5 | - *= require jquery.ui.gitlab | ||
| 6 | - *= require jquery.atwho | ||
| 7 | - *= require chosen | ||
| 8 | - *= require_self | ||
| 9 | - *= require main | ||
| 10 | -*/ |
| @@ -0,0 +1,52 @@ | @@ -0,0 +1,52 @@ | ||
| 1 | +/* | ||
| 2 | + * This is a manifest file that'll automatically include all the stylesheets available in this directory | ||
| 3 | + * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at | ||
| 4 | + * the top of the compiled file, but it's generally better to create a new file per style scope. | ||
| 5 | + *= require jquery.ui.gitlab | ||
| 6 | + *= require jquery.atwho | ||
| 7 | + *= require chosen | ||
| 8 | + *= require_self | ||
| 9 | +*/ | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * GitLab bootstrap: | ||
| 13 | + */ | ||
| 14 | +@import "gitlab_bootstrap.scss"; | ||
| 15 | + | ||
| 16 | +@import "common.scss"; | ||
| 17 | +@import "ref_select.scss"; | ||
| 18 | + | ||
| 19 | +@import "sections/header.scss"; | ||
| 20 | +@import "sections/nav.scss"; | ||
| 21 | +@import "sections/commits.scss"; | ||
| 22 | +@import "sections/issues.scss"; | ||
| 23 | +@import "sections/projects.scss"; | ||
| 24 | +@import "sections/snippets.scss"; | ||
| 25 | +@import "sections/votes.scss"; | ||
| 26 | +@import "sections/merge_requests.scss"; | ||
| 27 | +@import "sections/graph.scss"; | ||
| 28 | +@import "sections/events.scss"; | ||
| 29 | +@import "sections/themes.scss"; | ||
| 30 | +@import "sections/tree.scss"; | ||
| 31 | +@import "sections/notes.scss"; | ||
| 32 | +@import "sections/profile.scss"; | ||
| 33 | +@import "sections/login.scss"; | ||
| 34 | +@import "sections/editor.scss"; | ||
| 35 | + | ||
| 36 | +@import "highlight/white.scss"; | ||
| 37 | +@import "highlight/dark.scss"; | ||
| 38 | + | ||
| 39 | +/** | ||
| 40 | + * UI themes: | ||
| 41 | + */ | ||
| 42 | +@import "themes/ui_basic.scss"; | ||
| 43 | +@import "themes/ui_mars.scss"; | ||
| 44 | +@import "themes/ui_modern.scss"; | ||
| 45 | +@import "themes/ui_gray.scss"; | ||
| 46 | +@import "themes/ui_color.scss"; | ||
| 47 | + | ||
| 48 | +/** | ||
| 49 | + * Styles for JS behaviors. | ||
| 50 | + */ | ||
| 51 | +@import "behaviors.scss"; | ||
| 52 | + |
app/assets/stylesheets/common.scss
| @@ -13,20 +13,12 @@ body { | @@ -13,20 +13,12 @@ body { | ||
| 13 | margin: 0 0; | 13 | margin: 0 0; |
| 14 | } | 14 | } |
| 15 | 15 | ||
| 16 | -.container .sidebar { | ||
| 17 | - width: 200px; | ||
| 18 | - height: 100%; | ||
| 19 | - min-height: 450px; | ||
| 20 | - float: right; | ||
| 21 | -} | ||
| 22 | - | ||
| 23 | - | ||
| 24 | .visible_link, | 16 | .visible_link, |
| 25 | .author_link { | 17 | .author_link { |
| 26 | color: $link_color; | 18 | color: $link_color; |
| 27 | } | 19 | } |
| 28 | 20 | ||
| 29 | -.help li { color:#111 } | 21 | +.help li { color:$style_color; } |
| 30 | 22 | ||
| 31 | .back_link { | 23 | .back_link { |
| 32 | text-decoration: underline; | 24 | text-decoration: underline; |
| @@ -65,6 +57,9 @@ table a code { | @@ -65,6 +57,9 @@ table a code { | ||
| 65 | background: url(ajax_loader.gif) no-repeat center center; | 57 | background: url(ajax_loader.gif) no-repeat center center; |
| 66 | width: 40px; | 58 | width: 40px; |
| 67 | height: 40px; | 59 | height: 40px; |
| 60 | + &.loading-gray { | ||
| 61 | + background: url(ajax_loader_gray.gif) no-repeat center center; | ||
| 62 | + } | ||
| 68 | } | 63 | } |
| 69 | 64 | ||
| 70 | /** FLASH message **/ | 65 | /** FLASH message **/ |
| @@ -96,28 +91,17 @@ table a code { | @@ -96,28 +91,17 @@ table a code { | ||
| 96 | margin-right:50px | 91 | margin-right:50px |
| 97 | } | 92 | } |
| 98 | 93 | ||
| 99 | -.handle:hover { | ||
| 100 | - cursor: move; | ||
| 101 | -} | ||
| 102 | - | ||
| 103 | span.update-author { | 94 | span.update-author { |
| 104 | display: block; | 95 | display: block; |
| 105 | -} | ||
| 106 | -span.update-author { | ||
| 107 | color: #999; | 96 | color: #999; |
| 108 | font-weight: normal; | 97 | font-weight: normal; |
| 109 | font-style: italic; | 98 | font-style: italic; |
| 110 | -} | ||
| 111 | -span.update-author strong { | ||
| 112 | - font-weight: bold; | ||
| 113 | - font-style: normal; | 99 | + strong { |
| 100 | + font-weight: bold; | ||
| 101 | + font-style: normal; | ||
| 102 | + } | ||
| 114 | } | 103 | } |
| 115 | 104 | ||
| 116 | -/** UPDATE ITEM **/ | ||
| 117 | -span.update-author { | ||
| 118 | - display: block; | ||
| 119 | -} | ||
| 120 | -/** END UPDATE ITEM **/ | ||
| 121 | .dashboard-loader { | 105 | .dashboard-loader { |
| 122 | float: left; | 106 | float: left; |
| 123 | margin: 10px; | 107 | margin: 10px; |
| @@ -264,21 +248,6 @@ input.git_clone_url { | @@ -264,21 +248,6 @@ input.git_clone_url { | ||
| 264 | } | 248 | } |
| 265 | 249 | ||
| 266 | 250 | ||
| 267 | -/** bordered list **/ | ||
| 268 | -ul.bordered-list { | ||
| 269 | - margin: 5px 0px; | ||
| 270 | - padding: 0px; | ||
| 271 | - li { | ||
| 272 | - padding: 5px 0; | ||
| 273 | - border-bottom: 1px solid #EEE; | ||
| 274 | - overflow: hidden; | ||
| 275 | - display: block; | ||
| 276 | - margin: 0px; | ||
| 277 | - } | ||
| 278 | -} | ||
| 279 | - | ||
| 280 | -ul.bordered-list li:last-child { border:none } | ||
| 281 | - | ||
| 282 | .line_holder { | 251 | .line_holder { |
| 283 | &:hover { | 252 | &:hover { |
| 284 | td { | 253 | td { |
| @@ -316,98 +285,6 @@ p.time { | @@ -316,98 +285,6 @@ p.time { | ||
| 316 | } | 285 | } |
| 317 | 286 | ||
| 318 | 287 | ||
| 319 | -.ico { | ||
| 320 | - background: url("images.png") no-repeat -85px -77px; | ||
| 321 | - width: 19px; | ||
| 322 | - height: 16px; | ||
| 323 | - float: left; | ||
| 324 | - position: relative; | ||
| 325 | - margin-right: 10px; | ||
| 326 | - top: 8px; | ||
| 327 | - | ||
| 328 | - &.project { | ||
| 329 | - background-position: -37px -77px; | ||
| 330 | - } | ||
| 331 | - | ||
| 332 | - &.activities { | ||
| 333 | - background-position:-162px -22px; | ||
| 334 | - } | ||
| 335 | - &.projects { | ||
| 336 | - background-position:-209px -21px; | ||
| 337 | - } | ||
| 338 | -} | ||
| 339 | - | ||
| 340 | -.leftbar { | ||
| 341 | - h5, .title { | ||
| 342 | - padding: 5px 10px; | ||
| 343 | - } | ||
| 344 | - | ||
| 345 | - h4 { | ||
| 346 | - font-size: 14px; | ||
| 347 | - padding: 2px 10px; | ||
| 348 | - color: #666; | ||
| 349 | - border-bottom: 1px solid #f1f1f1; | ||
| 350 | - } | ||
| 351 | - a:last-child h4 { border: none; } | ||
| 352 | - | ||
| 353 | - a:hover { | ||
| 354 | - h4 { | ||
| 355 | - color: #111; | ||
| 356 | - background: $hover; | ||
| 357 | - border-color: #CCC; | ||
| 358 | - .ico.project { | ||
| 359 | - background-position:-209px -21px; | ||
| 360 | - } | ||
| 361 | - } | ||
| 362 | - } | ||
| 363 | - .bottom { | ||
| 364 | - padding: 10px; | ||
| 365 | - } | ||
| 366 | -} | ||
| 367 | - | ||
| 368 | -.votes { | ||
| 369 | - font-size: 13px; | ||
| 370 | - line-height: 15px; | ||
| 371 | - .progress { | ||
| 372 | - height: 4px; | ||
| 373 | - margin: 0; | ||
| 374 | - .bar { | ||
| 375 | - float: left; | ||
| 376 | - height: 100%; | ||
| 377 | - } | ||
| 378 | - .bar-success { | ||
| 379 | - @include linear-gradient(#62C462, #51A351); | ||
| 380 | - background-color: #468847; | ||
| 381 | - } | ||
| 382 | - .bar-danger { | ||
| 383 | - @include linear-gradient(#EE5F5B, #BD362F); | ||
| 384 | - background-color: #B94A48; | ||
| 385 | - } | ||
| 386 | - } | ||
| 387 | - .upvotes { | ||
| 388 | - display: inline-block; | ||
| 389 | - color: #468847; | ||
| 390 | - } | ||
| 391 | - .downvotes { | ||
| 392 | - display: inline-block; | ||
| 393 | - color: #B94A48; | ||
| 394 | - } | ||
| 395 | -} | ||
| 396 | -.votes-block { | ||
| 397 | - margin: 14px 6px 6px 0; | ||
| 398 | - .downvotes { | ||
| 399 | - float: right; | ||
| 400 | - } | ||
| 401 | -} | ||
| 402 | -.votes-inline { | ||
| 403 | - display: inline-block; | ||
| 404 | - margin: 0 8px; | ||
| 405 | - .progress { | ||
| 406 | - display: inline-block; | ||
| 407 | - padding: 0 0 2px; | ||
| 408 | - width: 45px; | ||
| 409 | - } | ||
| 410 | -} | ||
| 411 | 288 | ||
| 412 | /* Fix for readme code (stopped it from being yellow) */ | 289 | /* Fix for readme code (stopped it from being yellow) */ |
| 413 | .readme { | 290 | .readme { |
| @@ -420,7 +297,6 @@ p.time { | @@ -420,7 +297,6 @@ p.time { | ||
| 420 | } | 297 | } |
| 421 | } | 298 | } |
| 422 | 299 | ||
| 423 | - | ||
| 424 | .highlight_word { | 300 | .highlight_word { |
| 425 | background: #EEDC94; | 301 | background: #EEDC94; |
| 426 | } | 302 | } |
| @@ -428,23 +304,16 @@ p.time { | @@ -428,23 +304,16 @@ p.time { | ||
| 428 | .status_info { | 304 | .status_info { |
| 429 | font-size: 14px; | 305 | font-size: 14px; |
| 430 | padding: 5px 15px; | 306 | padding: 5px 15px; |
| 431 | - line-height: 24px; | ||
| 432 | - width: 60px; | 307 | + line-height: 26px; |
| 433 | text-align: center; | 308 | text-align: center; |
| 434 | - float: left; | ||
| 435 | - margin-right: 20px; | 309 | + float: right; |
| 310 | + position: relative; | ||
| 311 | + top: -5px; | ||
| 312 | + @include border-radius(4px); | ||
| 436 | 313 | ||
| 437 | - &.success { | ||
| 438 | - background: #5BB75B; | ||
| 439 | - color: white; | ||
| 440 | - text-shadow: 0 1px #111; | ||
| 441 | - border-color: #9A9; | ||
| 442 | - } | ||
| 443 | &.error { | 314 | &.error { |
| 444 | background: #DA4E49; | 315 | background: #DA4E49; |
| 445 | - border-color: #BD362F; | ||
| 446 | - color: white; | ||
| 447 | - text-shadow: 0 1px #111; | 316 | + color: #FFF; |
| 448 | } | 317 | } |
| 449 | } | 318 | } |
| 450 | 319 | ||
| @@ -463,16 +332,6 @@ p.time { | @@ -463,16 +332,6 @@ p.time { | ||
| 463 | height: 150px; | 332 | height: 150px; |
| 464 | } | 333 | } |
| 465 | 334 | ||
| 466 | -.gitlab_pagination { | ||
| 467 | - span a { color: $link_color; } | ||
| 468 | - .prev, .next, .current, .page a { | ||
| 469 | - padding: 10px; | ||
| 470 | - } | ||
| 471 | - .current { | ||
| 472 | - border-bottom: 2px solid $style_color; | ||
| 473 | - } | ||
| 474 | -} | ||
| 475 | - | ||
| 476 | // Fixes alignment on notes. | 335 | // Fixes alignment on notes. |
| 477 | .new_note { | 336 | .new_note { |
| 478 | label { | 337 | label { |
| @@ -647,9 +506,14 @@ pre { | @@ -647,9 +506,14 @@ pre { | ||
| 647 | } | 506 | } |
| 648 | } | 507 | } |
| 649 | 508 | ||
| 650 | -.milestone .progress { | ||
| 651 | - margin-bottom: 0; | ||
| 652 | - margin-top: 4px; | 509 | +.milestone { |
| 510 | + &.milestone-closed { | ||
| 511 | + background: #eee; | ||
| 512 | + } | ||
| 513 | + .progress { | ||
| 514 | + margin-bottom: 0; | ||
| 515 | + margin-top: 4px; | ||
| 516 | + } | ||
| 653 | } | 517 | } |
| 654 | 518 | ||
| 655 | .float-link { | 519 | .float-link { |
app/assets/stylesheets/fonts.scss
| @@ -1,7 +0,0 @@ | @@ -1,7 +0,0 @@ | ||
| 1 | -@font-face{ | ||
| 2 | - font-family: Korolev; | ||
| 3 | - src: font-url('korolev-medium-compressed.otf'); | ||
| 4 | -} | ||
| 5 | - | ||
| 6 | -/** Typo **/ | ||
| 7 | -$monospace: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace; | ||
| 8 | \ No newline at end of file | 0 | \ No newline at end of file |
| @@ -0,0 +1,26 @@ | @@ -0,0 +1,26 @@ | ||
| 1 | +/** Override bootstrap variables **/ | ||
| 2 | +$baseFontSize: 13px !default; | ||
| 3 | +$baseLineHeight: 18px !default; | ||
| 4 | + | ||
| 5 | +// BOOTSTRAP | ||
| 6 | +@import "bootstrap"; | ||
| 7 | +@import "bootstrap/responsive-utilities"; | ||
| 8 | +@import "bootstrap/responsive-1200px-min"; | ||
| 9 | + | ||
| 10 | +@import "font-awesome"; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * GitLab bootstrap. | ||
| 14 | + * Overrides some styles of twitter bootstrap. | ||
| 15 | + * Also give some common classes for GitLab app | ||
| 16 | + */ | ||
| 17 | +@import "gitlab_bootstrap/variables.scss"; | ||
| 18 | +@import "gitlab_bootstrap/fonts.scss"; | ||
| 19 | +@import "gitlab_bootstrap/mixins.scss"; | ||
| 20 | +@import "gitlab_bootstrap/common.scss"; | ||
| 21 | +@import "gitlab_bootstrap/typography.scss"; | ||
| 22 | +@import "gitlab_bootstrap/buttons.scss"; | ||
| 23 | +@import "gitlab_bootstrap/blocks.scss"; | ||
| 24 | +@import "gitlab_bootstrap/files.scss"; | ||
| 25 | +@import "gitlab_bootstrap/tables.scss"; | ||
| 26 | +@import "gitlab_bootstrap/lists.scss"; |
app/assets/stylesheets/gitlab_bootstrap/blocks.scss
| @@ -31,6 +31,7 @@ | @@ -31,6 +31,7 @@ | ||
| 31 | .middle_box_content, | 31 | .middle_box_content, |
| 32 | .bottom_box_content { | 32 | .bottom_box_content { |
| 33 | padding: 15px; | 33 | padding: 15px; |
| 34 | + word-wrap: break-word; | ||
| 34 | 35 | ||
| 35 | pre { | 36 | pre { |
| 36 | background: none !important; | 37 | background: none !important; |
| @@ -40,6 +41,15 @@ | @@ -40,6 +41,15 @@ | ||
| 40 | } | 41 | } |
| 41 | } | 42 | } |
| 42 | 43 | ||
| 44 | + .top_box_content { | ||
| 45 | + .box-title { | ||
| 46 | + color: $style_color; | ||
| 47 | + font-size: 18px; | ||
| 48 | + font-weight: normal; | ||
| 49 | + line-height: 28px; | ||
| 50 | + } | ||
| 51 | + } | ||
| 52 | + | ||
| 43 | .middle_box_content { | 53 | .middle_box_content { |
| 44 | @include border-radius(0); | 54 | @include border-radius(0); |
| 45 | border: none; | 55 | border: none; |
| @@ -64,7 +74,7 @@ | @@ -64,7 +74,7 @@ | ||
| 64 | 74 | ||
| 65 | border: 1px solid #eaeaea; | 75 | border: 1px solid #eaeaea; |
| 66 | @include border-radius(4px); | 76 | @include border-radius(4px); |
| 67 | - | 77 | + |
| 68 | border-color: #CCC; | 78 | border-color: #CCC; |
| 69 | @include solid-shade; | 79 | @include solid-shade; |
| 70 | 80 | ||
| @@ -83,6 +93,10 @@ | @@ -83,6 +93,10 @@ | ||
| 83 | border-top: 1px solid #eaeaea; | 93 | border-top: 1px solid #eaeaea; |
| 84 | border-bottom: 1px solid #bbb; | 94 | border-bottom: 1px solid #bbb; |
| 85 | 95 | ||
| 96 | + > a { | ||
| 97 | + text-shadow: 0 1px 1px #fff; | ||
| 98 | + } | ||
| 99 | + | ||
| 86 | &.small { | 100 | &.small { |
| 87 | line-height: 28px; | 101 | line-height: 28px; |
| 88 | font-size: 14px; | 102 | font-size: 14px; |
| @@ -138,19 +152,6 @@ | @@ -138,19 +152,6 @@ | ||
| 138 | } | 152 | } |
| 139 | } | 153 | } |
| 140 | 154 | ||
| 141 | - li, .wll { | ||
| 142 | - padding: 10px; | ||
| 143 | - &:first-child { | ||
| 144 | - @include border-radius(4px 4px 0 0); | ||
| 145 | - border-top: none; | ||
| 146 | - } | ||
| 147 | - | ||
| 148 | - &:last-child { | ||
| 149 | - @include border-radius(0 0 4px 4px); | ||
| 150 | - border: none; | ||
| 151 | - } | ||
| 152 | - } | ||
| 153 | - | ||
| 154 | .ui-box-body { | 155 | .ui-box-body { |
| 155 | padding: 10px; | 156 | padding: 10px; |
| 156 | } | 157 | } |
app/assets/stylesheets/gitlab_bootstrap/common.scss
| @@ -10,11 +10,6 @@ | @@ -10,11 +10,6 @@ | ||
| 10 | /** COMMON CLASSES **/ | 10 | /** COMMON CLASSES **/ |
| 11 | .left { float:left } | 11 | .left { float:left } |
| 12 | .right { float:right!important } | 12 | .right { float:right!important } |
| 13 | -.width-50p { width:50% } | ||
| 14 | -.width-49p { width:49% } | ||
| 15 | -.width-30p { width:30% } | ||
| 16 | -.width-65p { width:65% } | ||
| 17 | -.width-100p { width:100% } | ||
| 18 | .append-bottom-10 { margin-bottom:10px } | 13 | .append-bottom-10 { margin-bottom:10px } |
| 19 | .append-bottom-20 { margin-bottom:20px } | 14 | .append-bottom-20 { margin-bottom:20px } |
| 20 | .prepend-top-10 { margin-top:10px } | 15 | .prepend-top-10 { margin-top:10px } |
| @@ -30,6 +25,7 @@ | @@ -30,6 +25,7 @@ | ||
| 30 | .borders { border: 1px solid #ccc; @include shade; } | 25 | .borders { border: 1px solid #ccc; @include shade; } |
| 31 | .hint { font-style: italic; color: #999; } | 26 | .hint { font-style: italic; color: #999; } |
| 32 | .light { color: #888 } | 27 | .light { color: #888 } |
| 28 | +.tiny { font-weight: normal } | ||
| 33 | 29 | ||
| 34 | /** PILLS & TABS**/ | 30 | /** PILLS & TABS**/ |
| 35 | .nav-pills a:hover { background-color: #888; } | 31 | .nav-pills a:hover { background-color: #888; } |
| @@ -99,18 +95,21 @@ input[type='search'].search-text-input { | @@ -99,18 +95,21 @@ input[type='search'].search-text-input { | ||
| 99 | border: 1px solid #ccc; | 95 | border: 1px solid #ccc; |
| 100 | } | 96 | } |
| 101 | 97 | ||
| 102 | -fieldset legend { font-size: 17px; } | ||
| 103 | - | ||
| 104 | -ul.nav.nav-projects-tabs { | ||
| 105 | - @extend .nav-tabs; | 98 | +input[type='text'].danger { |
| 99 | + background: #F2DEDE!important; | ||
| 100 | + border-color: #D66; | ||
| 101 | + text-shadow: 0 1px 1px #fff | ||
| 102 | +} | ||
| 106 | 103 | ||
| 107 | - padding-left: 8px; | 104 | +fieldset legend { font-size: 17px; } |
| 108 | 105 | ||
| 109 | - li { | ||
| 110 | - a { | ||
| 111 | - padding: 4px 20px; | ||
| 112 | - margin-top: 2px; | ||
| 113 | - border-color: #DDD; | ||
| 114 | - } | 106 | +/** PAGINATION **/ |
| 107 | +.gitlab_pagination { | ||
| 108 | + span a { color: $link_color; } | ||
| 109 | + .prev, .next, .current, .page a { | ||
| 110 | + padding: 10px; | ||
| 111 | + } | ||
| 112 | + .current { | ||
| 113 | + border-bottom: 2px solid $style_color; | ||
| 115 | } | 114 | } |
| 116 | } | 115 | } |
app/assets/stylesheets/gitlab_bootstrap/files.scss
| @@ -43,11 +43,15 @@ | @@ -43,11 +43,15 @@ | ||
| 43 | padding: 0 4px; | 43 | padding: 0 4px; |
| 44 | } | 44 | } |
| 45 | padding: 20px; | 45 | padding: 20px; |
| 46 | - h1, h2 { | ||
| 47 | - line-height: 46px; | ||
| 48 | - } | ||
| 49 | - h3, h4 { | ||
| 50 | - line-height: 40px; | 46 | + |
| 47 | + h1 { font-size: 26px; line-height: 46px; } | ||
| 48 | + h2 { font-size: 22px; line-height: 42px; } | ||
| 49 | + h3 { font-size: 20px; line-height: 40px; } | ||
| 50 | + h4 { font-size: 18px; line-height: 32px; } | ||
| 51 | + h5 { font-size: 16px; line-height: 26px; } | ||
| 52 | + | ||
| 53 | + .white .highlight pre { | ||
| 54 | + background: #f5f5f5; | ||
| 51 | } | 55 | } |
| 52 | } | 56 | } |
| 53 | 57 |
| @@ -0,0 +1,7 @@ | @@ -0,0 +1,7 @@ | ||
| 1 | +@font-face{ | ||
| 2 | + font-family: Korolev; | ||
| 3 | + src: font-url('korolev-medium-compressed.otf'); | ||
| 4 | +} | ||
| 5 | + | ||
| 6 | +/** Typo **/ | ||
| 7 | +$monospace: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace; | ||
| 0 | \ No newline at end of file | 8 | \ No newline at end of file |
app/assets/stylesheets/gitlab_bootstrap/lists.scss
| 1 | -/** LISTS **/ | ||
| 2 | - | ||
| 3 | -ul { | ||
| 4 | - /** | ||
| 5 | - * List li block element #1 | ||
| 6 | - * | ||
| 7 | - */ | ||
| 8 | - .wll { | 1 | +/** |
| 2 | + * Well styled list | ||
| 3 | + * | ||
| 4 | + */ | ||
| 5 | +.well-list { | ||
| 6 | + margin: 0; | ||
| 7 | + list-style: none; | ||
| 8 | + li { | ||
| 9 | background-color: #FFF; | 9 | background-color: #FFF; |
| 10 | - padding: 10px 5px; | 10 | + padding: 10px; |
| 11 | min-height: 20px; | 11 | min-height: 20px; |
| 12 | border-bottom: 1px solid #eee; | 12 | border-bottom: 1px solid #eee; |
| 13 | border-bottom: 1px solid rgba(0, 0, 0, 0.05); | 13 | border-bottom: 1px solid rgba(0, 0, 0, 0.05); |
| 14 | 14 | ||
| 15 | + &.disabled { | ||
| 16 | + color: #888; | ||
| 17 | + } | ||
| 18 | + | ||
| 15 | &.smoke { background-color: #f5f5f5; } | 19 | &.smoke { background-color: #f5f5f5; } |
| 20 | + | ||
| 16 | &:hover { | 21 | &:hover { |
| 17 | background: $hover; | 22 | background: $hover; |
| 18 | border-bottom: 1px solid #ADF; | 23 | border-bottom: 1px solid #ADF; |
| 19 | } | 24 | } |
| 20 | - &:last-child { border:none } | 25 | + |
| 26 | + &:first-child { | ||
| 27 | + @include border-radius(4px 4px 0 0); | ||
| 28 | + border-top: none; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + &:last-child { | ||
| 32 | + @include border-radius(0 0 4px 4px); | ||
| 33 | + border: none; | ||
| 34 | + } | ||
| 35 | + | ||
| 21 | .author { color: #999; } | 36 | .author { color: #999; } |
| 22 | 37 | ||
| 23 | p { | 38 | p { |
| @@ -29,6 +44,11 @@ ul { | @@ -29,6 +44,11 @@ ul { | ||
| 29 | top: 3px; | 44 | top: 3px; |
| 30 | } | 45 | } |
| 31 | } | 46 | } |
| 47 | + | ||
| 48 | + .well-title { | ||
| 49 | + font-size: 14px; | ||
| 50 | + line-height: 18px; | ||
| 51 | + } | ||
| 32 | } | 52 | } |
| 33 | } | 53 | } |
| 34 | 54 | ||
| @@ -39,3 +59,17 @@ ol, ul { | @@ -39,3 +59,17 @@ ol, ul { | ||
| 39 | } | 59 | } |
| 40 | } | 60 | } |
| 41 | } | 61 | } |
| 62 | + | ||
| 63 | +/** light list with border-bottom between li **/ | ||
| 64 | +ul.bordered-list { | ||
| 65 | + margin: 5px 0px; | ||
| 66 | + padding: 0px; | ||
| 67 | + li { | ||
| 68 | + padding: 5px 0; | ||
| 69 | + border-bottom: 1px solid #EEE; | ||
| 70 | + overflow: hidden; | ||
| 71 | + display: block; | ||
| 72 | + margin: 0px; | ||
| 73 | + &:last-child { border:none } | ||
| 74 | + } | ||
| 75 | +} |
| @@ -0,0 +1,69 @@ | @@ -0,0 +1,69 @@ | ||
| 1 | +/** | ||
| 2 | + * Generic mixins | ||
| 3 | + */ | ||
| 4 | + @mixin box-shadow($shadow) { | ||
| 5 | + -webkit-box-shadow: $shadow; | ||
| 6 | + -moz-box-shadow: $shadow; | ||
| 7 | + -ms-box-shadow: $shadow; | ||
| 8 | + -o-box-shadow: $shadow; | ||
| 9 | + box-shadow: $shadow; | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +@mixin border-radius($radius) { | ||
| 13 | + -webkit-border-radius: $radius; | ||
| 14 | + -moz-border-radius: $radius; | ||
| 15 | + -ms-border-radius: $radius; | ||
| 16 | + -o-border-radius: $radius; | ||
| 17 | + border-radius: $radius; | ||
| 18 | +} | ||
| 19 | + | ||
| 20 | +@mixin linear-gradient($from, $to) { | ||
| 21 | + background-image: -webkit-gradient(linear, 0 0, 0 100%, from($from), to($to)); | ||
| 22 | + background-image: -webkit-linear-gradient($from, $to); | ||
| 23 | + background-image: -moz-linear-gradient($from, $to); | ||
| 24 | + background-image: -o-linear-gradient($from, $to); | ||
| 25 | +} | ||
| 26 | + | ||
| 27 | +/** | ||
| 28 | + * Prefilled mixins | ||
| 29 | + * Mixins with fixed values | ||
| 30 | + */ | ||
| 31 | +@mixin bg-light-gray-gradient { | ||
| 32 | + background: #f1f1f1; | ||
| 33 | + background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #f5f5f5), to(#e1e1e1)); | ||
| 34 | + background-image: -webkit-linear-gradient(#f5f5f5 6.6%, #e1e1e1); | ||
| 35 | + background-image: -moz-linear-gradient(#f5f5f5 6.6%, #e1e1e1); | ||
| 36 | + background-image: -o-linear-gradient(#f5f5f5 6.6%, #e1e1e1); | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +@mixin bg-gray-gradient { | ||
| 40 | + background: #eee; | ||
| 41 | + background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); | ||
| 42 | + background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); | ||
| 43 | + background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); | ||
| 44 | + background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +@mixin bg-dark-gray-gradient { | ||
| 48 | + background: #eee; | ||
| 49 | + background-image: -webkit-linear-gradient(#e9e9e9, #d7d7d7); | ||
| 50 | + background-image: -moz-linear-gradient(#e9e9e9, #d7d7d7); | ||
| 51 | + background-image: -o-linear-gradient(#e9e9e9, #d7d7d7); | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +@mixin shade { | ||
| 55 | + @include box-shadow(0 0 3px #ddd); | ||
| 56 | +} | ||
| 57 | + | ||
| 58 | +@mixin solid-shade { | ||
| 59 | + @include box-shadow(0 0 0 3px #f1f1f1); | ||
| 60 | +} | ||
| 61 | + | ||
| 62 | +@mixin header-font { | ||
| 63 | + color: $style_color; | ||
| 64 | + text-shadow: 0 1px 1px #FFF; | ||
| 65 | + font-family: 'Korolev', sans-serif; | ||
| 66 | + font-size: 28px; | ||
| 67 | + line-height: 48px; | ||
| 68 | + font-weight: normal; | ||
| 69 | +} |
app/assets/stylesheets/highlight/dark.scss
| 1 | .black .highlight { | 1 | .black .highlight { |
| 2 | + background-color: #333; | ||
| 2 | pre { | 3 | pre { |
| 3 | - background-color: #333; | ||
| 4 | color: #eee; | 4 | color: #eee; |
| 5 | + background: inherit; | ||
| 5 | } | 6 | } |
| 6 | 7 | ||
| 7 | .hll { display: block; background-color: darken($hover, 65%) } | 8 | .hll { display: block; background-color: darken($hover, 65%) } |
app/assets/stylesheets/jquery.ui.gitlab.css
| 1 | -/* | ||
| 2 | - * jQuery UI CSS Framework 1.8.7 | ||
| 3 | - * | ||
| 4 | - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) | ||
| 5 | - * Dual licensed under the MIT or GPL Version 2 licenses. | ||
| 6 | - * http://jquery.org/license | ||
| 7 | - * | ||
| 8 | - * http://docs.jquery.com/UI/Theming/API | ||
| 9 | - */ | ||
| 10 | - | ||
| 11 | -/* Layout helpers | ||
| 12 | -----------------------------------*/ | ||
| 13 | -.ui-helper-hidden { display: none; } | ||
| 14 | -.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } | ||
| 15 | -.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } | ||
| 16 | -.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } | ||
| 17 | -.ui-helper-clearfix { display: inline-block; } | ||
| 18 | -/* required comment for clearfix to work in Opera \*/ | ||
| 19 | -* html .ui-helper-clearfix { height:1%; } | ||
| 20 | -.ui-helper-clearfix { display:block; } | ||
| 21 | -/* end clearfix */ | ||
| 22 | -.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } | ||
| 23 | - | ||
| 24 | - | ||
| 25 | /* Interaction Cues | 1 | /* Interaction Cues |
| 26 | ----------------------------------*/ | 2 | ----------------------------------*/ |
| 27 | .ui-state-disabled { cursor: default !important; } | 3 | .ui-state-disabled { cursor: default !important; } |
| @@ -141,26 +117,6 @@ | @@ -141,26 +117,6 @@ | ||
| 141 | .ui-widget-overlay { background: #262b33; opacity: .70;filter:Alpha(Opacity=70); } | 117 | .ui-widget-overlay { background: #262b33; opacity: .70;filter:Alpha(Opacity=70); } |
| 142 | .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; } | 118 | .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; } |
| 143 | /* | 119 | /* |
| 144 | - * jQuery UI Resizable 1.8.7 | ||
| 145 | - * | ||
| 146 | - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) | ||
| 147 | - * Dual licensed under the MIT or GPL Version 2 licenses. | ||
| 148 | - * http://jquery.org/license | ||
| 149 | - * | ||
| 150 | - * http://docs.jquery.com/UI/Resizable#theming | ||
| 151 | - */ | ||
| 152 | -.ui-resizable { position: relative;} | ||
| 153 | -.ui-resizable-handle { position: absolute; font-size: 0.1px; z-index: 999; display: block;} | ||
| 154 | -.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } | ||
| 155 | -.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } | ||
| 156 | -.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } | ||
| 157 | -.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } | ||
| 158 | -.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } | ||
| 159 | -.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } | ||
| 160 | -.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } | ||
| 161 | -.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } | ||
| 162 | -.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;} | ||
| 163 | -/* | ||
| 164 | * jQuery UI Selectable 1.8.7 | 120 | * jQuery UI Selectable 1.8.7 |
| 165 | * | 121 | * |
| 166 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) | 122 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) |
| @@ -240,34 +196,7 @@ | @@ -240,34 +196,7 @@ | ||
| 240 | cursor: pointer; | 196 | cursor: pointer; |
| 241 | font-weight: bold; | 197 | font-weight: bold; |
| 242 | } | 198 | } |
| 243 | -/* | ||
| 244 | - * jQuery UI Slider 1.8.7 | ||
| 245 | - * | ||
| 246 | - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) | ||
| 247 | - * Dual licensed under the MIT or GPL Version 2 licenses. | ||
| 248 | - * http://jquery.org/license | ||
| 249 | - * | ||
| 250 | - * http://docs.jquery.com/UI/Slider#theming | ||
| 251 | - */ | ||
| 252 | -.ui-slider { position: relative; text-align: left; background: #d7d7d7; z-index: 1; } | ||
| 253 | -.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; } | ||
| 254 | -.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; } | ||
| 255 | -.ui-slider .ui-state-hover, .ui-slider .ui-state-active { background-position: 0 0; } | ||
| 256 | -.ui-slider .ui-slider-range { background: #a3cae0; position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } | ||
| 257 | -.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; } | ||
| 258 | 199 | ||
| 259 | - | ||
| 260 | -.ui-slider-horizontal { height: 5px; } | ||
| 261 | -.ui-slider-horizontal .ui-slider-handle { top: -8px; margin-left: -13px; } | ||
| 262 | -.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } | ||
| 263 | -.ui-slider-horizontal .ui-slider-range-min { left: 0; } | ||
| 264 | -.ui-slider-horizontal .ui-slider-range-max { right: 0; } | ||
| 265 | - | ||
| 266 | -.ui-slider-vertical { width: 5px; height: 100px; } | ||
| 267 | -.ui-slider-vertical .ui-slider-handle { left: -8px; margin-left: 0; margin-bottom: -13px; } | ||
| 268 | -.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } | ||
| 269 | -.ui-slider-vertical .ui-slider-range-min { bottom: 0; } | ||
| 270 | -.ui-slider-vertical .ui-slider-range-max { top: 0; } | ||
| 271 | /* | 200 | /* |
| 272 | * jQuery UI Datepicker 1.8.7 | 201 | * jQuery UI Datepicker 1.8.7 |
| 273 | * | 202 | * |
| @@ -326,45 +255,3 @@ | @@ -326,45 +255,3 @@ | ||
| 326 | .ui-datepicker table .ui-state-highlight { border-color: #ADE; } | 255 | .ui-datepicker table .ui-state-highlight { border-color: #ADE; } |
| 327 | .ui-datepicker-calendar .ui-state-default { background: transparent; border-color: #FFF; } | 256 | .ui-datepicker-calendar .ui-state-default { background: transparent; border-color: #FFF; } |
| 328 | .ui-datepicker-calendar .ui-state-active { background: #D9EDF7; border-color: #ADE; color: #3A89A3; font-weight: bold; text-shadow: 0 1px 1px #fff; } | 257 | .ui-datepicker-calendar .ui-state-active { background: #D9EDF7; border-color: #ADE; color: #3A89A3; font-weight: bold; text-shadow: 0 1px 1px #fff; } |
| 329 | - | ||
| 330 | -/* with multiple calendars */ | ||
| 331 | -.ui-datepicker.ui-datepicker-multi { width:auto; } | ||
| 332 | -.ui-datepicker-multi .ui-datepicker-group { float:left; } | ||
| 333 | -.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } | ||
| 334 | -.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } | ||
| 335 | -.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } | ||
| 336 | -.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } | ||
| 337 | -.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } | ||
| 338 | -.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } | ||
| 339 | -.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } | ||
| 340 | -.ui-datepicker-row-break { clear:both; width:100%; } | ||
| 341 | - | ||
| 342 | - | ||
| 343 | -/* Extra Input Field Styling */ | ||
| 344 | -.ui-form textarea, .ui-form input:not([type="submit"]):not([type="button"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]) { | ||
| 345 | - padding: 3px; | ||
| 346 | - -webkit-border-radius: 2px; | ||
| 347 | - -moz-border-radius: 2px; | ||
| 348 | - border-radius: 2px; | ||
| 349 | - border: 1px solid #cecece; | ||
| 350 | - outline: none; | ||
| 351 | - -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.1) inset, 0 1px 0 rgba(255,255,255,0.2); | ||
| 352 | - -moz-box-shadow: 0 1px 3px rgba(0,0,0,0.1) inset, 0 1px 0 rgba(255,255,255,0.2); | ||
| 353 | - box-shadow: 0 1px 3px rgba(0,0,0,0.1) inset, 0 1px 0 rgba(255,255,255,0.2); | ||
| 354 | - -webkit-transition: all 250ms ease-in-out; | ||
| 355 | - -moz-transition: all 250ms ease-in-out; | ||
| 356 | - -o-transition: all 250ms ease-in-out; | ||
| 357 | - transition: all 250ms ease-in-out; | ||
| 358 | -} | ||
| 359 | -.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 { | ||
| 360 | - border: 1px solid #bdbdbd; | ||
| 361 | - -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.2) inset, 0 1px 0 rgba(255,255,255,0.2); | ||
| 362 | - -moz-box-shadow: 0 1px 3px rgba(0,0,0,0.2) inset, 0 1px 0 rgba(255,255,255,0.2); | ||
| 363 | - box-shadow: 0 1px 3px rgba(0,0,0,0.2) inset, 0 1px 0 rgba(255,255,255,0.2); | ||
| 364 | -} | ||
| 365 | -.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 { | ||
| 366 | - border: 1px solid #95bdd4; | ||
| 367 | - -webkit-box-shadow: 0 2px 3px rgba(161,202,226,0.5) inset, 0 1px 0 rgba(255,255,255,0.2); | ||
| 368 | - -moz-box-shadow: 0 2px 3px rgba(161,202,226,0.5) inset, 0 1px 0 rgba(255,255,255,0.2); | ||
| 369 | - box-shadow: 0 2px 3px rgba(161,202,226,0.5) inset, 0 1px 0 rgba(255,255,255,0.2); | ||
| 370 | -} |
app/assets/stylesheets/main.scss
| @@ -1,144 +0,0 @@ | @@ -1,144 +0,0 @@ | ||
| 1 | -/** Override bootstrap variables **/ | ||
| 2 | -$baseFontSize: 13px !default; | ||
| 3 | -$baseLineHeight: 18px !default; | ||
| 4 | - | ||
| 5 | -// BOOTSTRAP | ||
| 6 | -@import "bootstrap"; | ||
| 7 | -@import "bootstrap/responsive-utilities"; | ||
| 8 | -@import "bootstrap/responsive-1200px-min"; | ||
| 9 | - | ||
| 10 | -// FONT AWESOME | ||
| 11 | -@import "font-awesome"; | ||
| 12 | - | ||
| 13 | -/** | ||
| 14 | - * Variables | ||
| 15 | - * Contains colors | ||
| 16 | - */ | ||
| 17 | -@import "variables.scss"; | ||
| 18 | - | ||
| 19 | -/** | ||
| 20 | - * Custom fonts | ||
| 21 | - * Contains @font-face font Korolev and default $monotype | ||
| 22 | - */ | ||
| 23 | -@import "fonts.scss"; | ||
| 24 | - | ||
| 25 | -/** | ||
| 26 | - * General mixins. | ||
| 27 | - * Contains rounded borders, gradients and shades | ||
| 28 | - */ | ||
| 29 | -@import "mixins.scss"; | ||
| 30 | - | ||
| 31 | -/** | ||
| 32 | - * Header of application. | ||
| 33 | - * Contain application logo, search panel, profile icon | ||
| 34 | - */ | ||
| 35 | -@import "sections/header.scss"; | ||
| 36 | - | ||
| 37 | -/** | ||
| 38 | - * Navigation menu of application. | ||
| 39 | - * Panel with links to pages depends on project, profile or admin area | ||
| 40 | - */ | ||
| 41 | -@import "sections/nav.scss"; | ||
| 42 | - | ||
| 43 | -/** | ||
| 44 | - * This file represent some UI that can be changed | ||
| 45 | - * during web app restyle or theme select. | ||
| 46 | - * | ||
| 47 | - * Next items should be placed there | ||
| 48 | - * - link, button colors | ||
| 49 | - * - header restyles | ||
| 50 | - * - main menu restyles | ||
| 51 | - * | ||
| 52 | - */ | ||
| 53 | -@import "themes/ui_basic.scss"; | ||
| 54 | - | ||
| 55 | -/** | ||
| 56 | - * UI themes: | ||
| 57 | - */ | ||
| 58 | -@import "themes/ui_mars.scss"; | ||
| 59 | -@import "themes/ui_modern.scss"; | ||
| 60 | -@import "themes/ui_gray.scss"; | ||
| 61 | -@import "themes/ui_color.scss"; | ||
| 62 | - | ||
| 63 | -/** | ||
| 64 | - * GitLab bootstrap. | ||
| 65 | - * Overrides some styles of twitter bootstrap. | ||
| 66 | - * Also give some common classes for GitLab app | ||
| 67 | - */ | ||
| 68 | -@import "gitlab_bootstrap/common.scss"; | ||
| 69 | -@import "gitlab_bootstrap/typography.scss"; | ||
| 70 | -@import "gitlab_bootstrap/buttons.scss"; | ||
| 71 | -@import "gitlab_bootstrap/blocks.scss"; | ||
| 72 | -@import "gitlab_bootstrap/files.scss"; | ||
| 73 | -@import "gitlab_bootstrap/tables.scss"; | ||
| 74 | -@import "gitlab_bootstrap/lists.scss"; | ||
| 75 | - | ||
| 76 | - | ||
| 77 | -/** | ||
| 78 | - * Most of application styles placed here. | ||
| 79 | - * This file represent common UI that should not be changed between themes | ||
| 80 | - * or project restyling like form width or user avatar class or commit title | ||
| 81 | - * | ||
| 82 | - * TODO: clean it | ||
| 83 | - */ | ||
| 84 | -@import "common.scss"; | ||
| 85 | - | ||
| 86 | -/** | ||
| 87 | - * Styles necessary to support JS behaviours. | ||
| 88 | - */ | ||
| 89 | -@import "behaviors.scss"; | ||
| 90 | - | ||
| 91 | -/** | ||
| 92 | - * Styles related to specific part of app | ||
| 93 | - */ | ||
| 94 | -@import "sections/commits.scss"; | ||
| 95 | -@import "sections/issues.scss"; | ||
| 96 | -@import "sections/projects.scss"; | ||
| 97 | -@import "sections/merge_requests.scss"; | ||
| 98 | -@import "sections/graph.scss"; | ||
| 99 | -@import "sections/events.scss"; | ||
| 100 | -@import "sections/themes.scss"; | ||
| 101 | - | ||
| 102 | -/** | ||
| 103 | - * This scss file redefine chozen selectbox styles for | ||
| 104 | - * project Branch/Tag select element | ||
| 105 | - */ | ||
| 106 | -@import "ref_select.scss"; | ||
| 107 | - | ||
| 108 | -/** | ||
| 109 | - * Code (files list) styles. Browsing project files there | ||
| 110 | - */ | ||
| 111 | -@import "sections/tree.scss"; | ||
| 112 | - | ||
| 113 | -/** | ||
| 114 | - * This file represent notes(comments) styles | ||
| 115 | - */ | ||
| 116 | -@import "sections/notes.scss"; | ||
| 117 | - | ||
| 118 | -/** | ||
| 119 | - * This file represent profile styles | ||
| 120 | - */ | ||
| 121 | -@import "sections/profile.scss"; | ||
| 122 | - | ||
| 123 | -/** | ||
| 124 | - * Devise styles | ||
| 125 | - */ | ||
| 126 | -@import "sections/login.scss"; | ||
| 127 | - | ||
| 128 | -/** | ||
| 129 | - * CODE HIGHTLIGHT BASE | ||
| 130 | - * | ||
| 131 | - */ | ||
| 132 | -@import "highlight/white.scss"; | ||
| 133 | - | ||
| 134 | -/** | ||
| 135 | - * CODE HIGHTLIGHT DARK schema | ||
| 136 | - * | ||
| 137 | - */ | ||
| 138 | -@import "highlight/dark.scss"; | ||
| 139 | - | ||
| 140 | -/** | ||
| 141 | - * File Editor styles | ||
| 142 | - * | ||
| 143 | - */ | ||
| 144 | -@import "sections/editor.scss"; |
app/assets/stylesheets/mixins.scss
| @@ -1,60 +0,0 @@ | @@ -1,60 +0,0 @@ | ||
| 1 | -/** | ||
| 2 | - * Generic mixins | ||
| 3 | - */ | ||
| 4 | - @mixin box-shadow($shadow) { | ||
| 5 | - -webkit-box-shadow: $shadow; | ||
| 6 | - -moz-box-shadow: $shadow; | ||
| 7 | - -ms-box-shadow: $shadow; | ||
| 8 | - -o-box-shadow: $shadow; | ||
| 9 | - box-shadow: $shadow; | ||
| 10 | -} | ||
| 11 | - | ||
| 12 | -@mixin border-radius($radius) { | ||
| 13 | - -webkit-border-radius: $radius; | ||
| 14 | - -moz-border-radius: $radius; | ||
| 15 | - -ms-border-radius: $radius; | ||
| 16 | - -o-border-radius: $radius; | ||
| 17 | - border-radius: $radius; | ||
| 18 | -} | ||
| 19 | - | ||
| 20 | -@mixin linear-gradient($from, $to) { | ||
| 21 | - background-image: -webkit-gradient(linear, 0 0, 0 100%, from($from), to($to)); | ||
| 22 | - background-image: -webkit-linear-gradient($from, $to); | ||
| 23 | - background-image: -moz-linear-gradient($from, $to); | ||
| 24 | - background-image: -o-linear-gradient($from, $to); | ||
| 25 | -} | ||
| 26 | - | ||
| 27 | -/** | ||
| 28 | - * Prefilled mixins | ||
| 29 | - * Mixins with fixed values | ||
| 30 | - */ | ||
| 31 | -@mixin bg-light-gray-gradient { | ||
| 32 | - background: #f1f1f1; | ||
| 33 | - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #f5f5f5), to(#e1e1e1)); | ||
| 34 | - background-image: -webkit-linear-gradient(#f5f5f5 6.6%, #e1e1e1); | ||
| 35 | - background-image: -moz-linear-gradient(#f5f5f5 6.6%, #e1e1e1); | ||
| 36 | - background-image: -o-linear-gradient(#f5f5f5 6.6%, #e1e1e1); | ||
| 37 | -} | ||
| 38 | - | ||
| 39 | -@mixin bg-gray-gradient { | ||
| 40 | - background: #eee; | ||
| 41 | - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); | ||
| 42 | - background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); | ||
| 43 | - background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); | ||
| 44 | - background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); | ||
| 45 | -} | ||
| 46 | - | ||
| 47 | -@mixin bg-dark-gray-gradient { | ||
| 48 | - background: #eee; | ||
| 49 | - background-image: -webkit-linear-gradient(#e9e9e9, #d7d7d7); | ||
| 50 | - background-image: -moz-linear-gradient(#e9e9e9, #d7d7d7); | ||
| 51 | - background-image: -o-linear-gradient(#e9e9e9, #d7d7d7); | ||
| 52 | -} | ||
| 53 | - | ||
| 54 | -@mixin shade { | ||
| 55 | - @include box-shadow(0 0 3px #ddd); | ||
| 56 | -} | ||
| 57 | - | ||
| 58 | -@mixin solid-shade { | ||
| 59 | - @include box-shadow(0 0 0 3px #f1f1f1); | ||
| 60 | -} | ||
| 61 | \ No newline at end of file | 0 | \ No newline at end of file |
app/assets/stylesheets/sections/commits.scss
| @@ -232,8 +232,6 @@ | @@ -232,8 +232,6 @@ | ||
| 232 | 232 | ||
| 233 | /** COMMIT ROW **/ | 233 | /** COMMIT ROW **/ |
| 234 | .commit { | 234 | .commit { |
| 235 | - @extend .wll; | ||
| 236 | - | ||
| 237 | .browse_code_link_holder { | 235 | .browse_code_link_holder { |
| 238 | @extend .span2; | 236 | @extend .span2; |
| 239 | float: right; | 237 | float: right; |
| @@ -305,3 +303,17 @@ | @@ -305,3 +303,17 @@ | ||
| 305 | color: #fff; | 303 | color: #fff; |
| 306 | font-family: $monospace; | 304 | font-family: $monospace; |
| 307 | } | 305 | } |
| 306 | + | ||
| 307 | + | ||
| 308 | +.commits-compare-switch{ | ||
| 309 | + background: url("switch_icon.png") no-repeat center center; | ||
| 310 | + width: 16px; | ||
| 311 | + height: 18px; | ||
| 312 | + text-indent: -9999px; | ||
| 313 | + float: left; | ||
| 314 | + margin-right: 9px; | ||
| 315 | + border: 1px solid #DDD; | ||
| 316 | + @include border-radius(4px); | ||
| 317 | + padding: 4px; | ||
| 318 | + background-color: #EEE; | ||
| 319 | +} |
app/assets/stylesheets/sections/events.scss
| @@ -31,7 +31,6 @@ | @@ -31,7 +31,6 @@ | ||
| 31 | * | 31 | * |
| 32 | */ | 32 | */ |
| 33 | .event-item { | 33 | .event-item { |
| 34 | - min-height: 40px; | ||
| 35 | border-bottom: 1px solid #eee; | 34 | border-bottom: 1px solid #eee; |
| 36 | .event-title { | 35 | .event-title { |
| 37 | color: #333; | 36 | color: #333; |
| @@ -50,14 +49,18 @@ | @@ -50,14 +49,18 @@ | ||
| 50 | } | 49 | } |
| 51 | } | 50 | } |
| 52 | .avatar { | 51 | .avatar { |
| 53 | - width: 32px; | 52 | + position: relative; |
| 53 | + top: -3px; | ||
| 54 | } | 54 | } |
| 55 | .event_icon { | 55 | .event_icon { |
| 56 | + position: relative; | ||
| 56 | float: right; | 57 | float: right; |
| 57 | border: 1px solid #EEE; | 58 | border: 1px solid #EEE; |
| 58 | padding: 5px; | 59 | padding: 5px; |
| 59 | @include border-radius(5px); | 60 | @include border-radius(5px); |
| 60 | background: #F9F9F9; | 61 | background: #F9F9F9; |
| 62 | + margin-left: 10px; | ||
| 63 | + top: -6px; | ||
| 61 | img { | 64 | img { |
| 62 | width: 20px; | 65 | width: 20px; |
| 63 | } | 66 | } |
| @@ -71,9 +74,8 @@ | @@ -71,9 +74,8 @@ | ||
| 71 | } | 74 | } |
| 72 | } | 75 | } |
| 73 | 76 | ||
| 74 | - padding: 15px 5px; | 77 | + padding: 16px 5px; |
| 75 | &:last-child { border:none } | 78 | &:last-child { border:none } |
| 76 | - .wll:hover { background:none } | ||
| 77 | 79 | ||
| 78 | .event_commits { | 80 | .event_commits { |
| 79 | margin-top: 5px; | 81 | margin-top: 5px; |
app/assets/stylesheets/sections/header.scss
| @@ -44,14 +44,9 @@ header { | @@ -44,14 +44,9 @@ header { | ||
| 44 | background: url('logo_dark.png') no-repeat 0px 2px; | 44 | background: url('logo_dark.png') no-repeat 0px 2px; |
| 45 | float: left; | 45 | float: left; |
| 46 | margin-left: 2px; | 46 | margin-left: 2px; |
| 47 | - font-size: 30px; | ||
| 48 | - line-height: 48px; | ||
| 49 | - font-weight: normal; | ||
| 50 | - color: $style_color; | ||
| 51 | - text-shadow: 0 1px 1px #FFF; | ||
| 52 | padding-left: 45px; | 47 | padding-left: 45px; |
| 53 | height: 40px; | 48 | height: 40px; |
| 54 | - font-family: 'Korolev', sans-serif; | 49 | + @include header-font; |
| 55 | } | 50 | } |
| 56 | } | 51 | } |
| 57 | } | 52 | } |
| @@ -66,12 +61,7 @@ header { | @@ -66,12 +61,7 @@ header { | ||
| 66 | float: left; | 61 | float: left; |
| 67 | margin: 0; | 62 | margin: 0; |
| 68 | margin-right: 30px; | 63 | margin-right: 30px; |
| 69 | - font-size: 30px; | ||
| 70 | - line-height: 48px; | ||
| 71 | - font-weight: normal; | ||
| 72 | - color: $style_color; | ||
| 73 | - text-shadow: 0 1px 1px #FFF; | ||
| 74 | - font-family: 'Korolev', sans-serif; | 64 | + @include header-font; |
| 75 | } | 65 | } |
| 76 | 66 | ||
| 77 | /** | 67 | /** |
| @@ -172,7 +162,7 @@ header { | @@ -172,7 +162,7 @@ header { | ||
| 172 | display: none; | 162 | display: none; |
| 173 | z-index: 100000; | 163 | z-index: 100000; |
| 174 | @include border-radius(4px); | 164 | @include border-radius(4px); |
| 175 | - width: 100px; | 165 | + width: 130px; |
| 176 | position: absolute; | 166 | position: absolute; |
| 177 | right: 5px; | 167 | right: 5px; |
| 178 | top: 38px; | 168 | top: 38px; |
| @@ -181,7 +171,7 @@ header { | @@ -181,7 +171,7 @@ header { | ||
| 181 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); | 171 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); |
| 182 | a { | 172 | a { |
| 183 | color: #fff; | 173 | color: #fff; |
| 184 | - padding: 7px 10px; | 174 | + padding: 12px 15px; |
| 185 | display: block; | 175 | display: block; |
| 186 | text-shadow: none; | 176 | text-shadow: none; |
| 187 | border-bottom: 1px solid #666; | 177 | border-bottom: 1px solid #666; |
| @@ -204,8 +194,8 @@ header { | @@ -204,8 +194,8 @@ header { | ||
| 204 | } | 194 | } |
| 205 | &:last-child { | 195 | &:last-child { |
| 206 | @include border-radius(0 0 5px 5px); | 196 | @include border-radius(0 0 5px 5px); |
| 207 | - border-bottom: 0; | ||
| 208 | - } | 197 | + border-bottom: 0; |
| 198 | + } | ||
| 209 | } | 199 | } |
| 210 | 200 | ||
| 211 | 201 |
app/assets/stylesheets/sections/issues.scss
app/assets/stylesheets/sections/merge_requests.scss
app/assets/stylesheets/sections/nav.scss
| @@ -3,15 +3,13 @@ | @@ -3,15 +3,13 @@ | ||
| 3 | * | 3 | * |
| 4 | */ | 4 | */ |
| 5 | ul.main_menu { | 5 | ul.main_menu { |
| 6 | - @include border-radius(4px); | ||
| 7 | margin: auto; | 6 | margin: auto; |
| 8 | margin: 30px 0; | 7 | margin: 30px 0; |
| 9 | - border: 1px solid #BBB; | 8 | + margin-top: 10px; |
| 9 | + border-bottom: 1px solid #DDD; | ||
| 10 | height: 37px; | 10 | height: 37px; |
| 11 | - @include bg-gray-gradient; | ||
| 12 | position: relative; | 11 | position: relative; |
| 13 | overflow: hidden; | 12 | overflow: hidden; |
| 14 | - @include shade; | ||
| 15 | .count { | 13 | .count { |
| 16 | position: relative; | 14 | position: relative; |
| 17 | top: -1px; | 15 | top: -1px; |
| @@ -24,9 +22,6 @@ ul.main_menu { | @@ -24,9 +22,6 @@ ul.main_menu { | ||
| 24 | line-height: 14px; | 22 | line-height: 14px; |
| 25 | text-align: center; | 23 | text-align: center; |
| 26 | color: #777; | 24 | color: #777; |
| 27 | - background: #f2f2f2; | ||
| 28 | - border-top: 1px solid #CCC; | ||
| 29 | - @include border-radius(8px); | ||
| 30 | } | 25 | } |
| 31 | .label { | 26 | .label { |
| 32 | background: $hover; | 27 | background: $hover; |
| @@ -38,23 +33,10 @@ ul.main_menu { | @@ -38,23 +33,10 @@ ul.main_menu { | ||
| 38 | margin: 0; | 33 | margin: 0; |
| 39 | display: table-cell; | 34 | display: table-cell; |
| 40 | width: 1%; | 35 | width: 1%; |
| 41 | - border-right: 1px solid #DDD; | ||
| 42 | - border-left: 1px solid #EEE; | ||
| 43 | - border-bottom: 2px solid #CFCFCF; | ||
| 44 | - | ||
| 45 | - &:first-child{ | ||
| 46 | - @include border-radius(5px 0 0 5px); | ||
| 47 | - border-left: 0; | ||
| 48 | - } | ||
| 49 | - | ||
| 50 | &.active { | 36 | &.active { |
| 51 | - background-color: #D5D5D5; | ||
| 52 | - border-right: 1px solid #BBB; | ||
| 53 | - border-left: 1px solid #BBB; | ||
| 54 | - @include border-radius(0 0 1px 1px); | ||
| 55 | - &:first-child{ | ||
| 56 | - border-bottom: none; | ||
| 57 | - border-left: none; | 37 | + border-bottom: 2px solid #474D57; |
| 38 | + a { | ||
| 39 | + color: $style_color; | ||
| 58 | } | 40 | } |
| 59 | } | 41 | } |
| 60 | 42 | ||
| @@ -73,10 +55,10 @@ ul.main_menu { | @@ -73,10 +55,10 @@ ul.main_menu { | ||
| 73 | a { | 55 | a { |
| 74 | display: block; | 56 | display: block; |
| 75 | text-align: center; | 57 | text-align: center; |
| 76 | - font-weight: bold; | 58 | + font-weight: normal; |
| 77 | height: 35px; | 59 | height: 35px; |
| 78 | line-height: 36px; | 60 | line-height: 36px; |
| 79 | - color: $style_color; | 61 | + color: #777; |
| 80 | text-shadow: 0 1px 1px white; | 62 | text-shadow: 0 1px 1px white; |
| 81 | padding: 0 10px; | 63 | padding: 0 10px; |
| 82 | } | 64 | } |
app/assets/stylesheets/sections/projects.scss
| @@ -4,12 +4,11 @@ | @@ -4,12 +4,11 @@ | ||
| 4 | } | 4 | } |
| 5 | 5 | ||
| 6 | .side { | 6 | .side { |
| 7 | - @extend .span4; | ||
| 8 | @extend .right; | 7 | @extend .right; |
| 9 | 8 | ||
| 10 | .groups_box, | 9 | .groups_box, |
| 11 | .projects_box { | 10 | .projects_box { |
| 12 | - h5 { | 11 | + > h5 { |
| 13 | color: $style_color; | 12 | color: $style_color; |
| 14 | font-size: 16px; | 13 | font-size: 16px; |
| 15 | text-shadow: 0 1px 1px #fff; | 14 | text-shadow: 0 1px 1px #fff; |
| @@ -17,37 +16,22 @@ | @@ -17,37 +16,22 @@ | ||
| 17 | line-height: 32px; | 16 | line-height: 32px; |
| 18 | font-size: 14px; | 17 | font-size: 14px; |
| 19 | } | 18 | } |
| 20 | - ul { | ||
| 21 | - li { | ||
| 22 | - padding: 0; | ||
| 23 | - a { | ||
| 24 | - display: block; | ||
| 25 | - .group_name { | ||
| 26 | - font-size: 14px; | ||
| 27 | - line-height: 18px; | ||
| 28 | - } | ||
| 29 | - .project_name { | ||
| 30 | - color: #4fa2bd; | ||
| 31 | - font-size: 14px; | ||
| 32 | - line-height: 18px; | ||
| 33 | - } | ||
| 34 | - .arrow { | ||
| 35 | - float: right; | ||
| 36 | - padding: 10px; | ||
| 37 | - margin: 0; | ||
| 38 | - } | ||
| 39 | - .last_activity { | ||
| 40 | - padding-top: 5px; | ||
| 41 | - display: block; | ||
| 42 | - span, strong { | ||
| 43 | - font-size: 12px; | ||
| 44 | - color: #666; | ||
| 45 | - } | ||
| 46 | - } | 19 | + .nav-projects-tabs li { padding: 0; } |
| 20 | + .well-list { | ||
| 21 | + .arrow { | ||
| 22 | + float: right; | ||
| 23 | + padding: 10px; | ||
| 24 | + margin: 0; | ||
| 25 | + } | ||
| 26 | + .last_activity { | ||
| 27 | + padding-top: 5px; | ||
| 28 | + display: block; | ||
| 29 | + span, strong { | ||
| 30 | + font-size: 12px; | ||
| 31 | + color: #666; | ||
| 47 | } | 32 | } |
| 48 | } | 33 | } |
| 49 | } | 34 | } |
| 50 | - @extend .leftbar; | ||
| 51 | @extend .ui-box; | 35 | @extend .ui-box; |
| 52 | } | 36 | } |
| 53 | } | 37 | } |
| @@ -117,3 +101,25 @@ | @@ -117,3 +101,25 @@ | ||
| 117 | } | 101 | } |
| 118 | 102 | ||
| 119 | } | 103 | } |
| 104 | + | ||
| 105 | +ul.nav.nav-projects-tabs { | ||
| 106 | + @extend .nav-tabs; | ||
| 107 | + | ||
| 108 | + padding-left: 8px; | ||
| 109 | + | ||
| 110 | + li { | ||
| 111 | + a { | ||
| 112 | + padding: 4px 20px; | ||
| 113 | + margin-top: 2px; | ||
| 114 | + border-color: #DDD; | ||
| 115 | + background-color: #EEE; | ||
| 116 | + text-shadow: 0 1px 1px white; | ||
| 117 | + color: #555; | ||
| 118 | + } | ||
| 119 | + &.active { | ||
| 120 | + a { | ||
| 121 | + font-weight: bold; | ||
| 122 | + } | ||
| 123 | + } | ||
| 124 | + } | ||
| 125 | +} |
| @@ -0,0 +1,43 @@ | @@ -0,0 +1,43 @@ | ||
| 1 | +.votes { | ||
| 2 | + font-size: 13px; | ||
| 3 | + line-height: 15px; | ||
| 4 | + .progress { | ||
| 5 | + height: 4px; | ||
| 6 | + margin: 0; | ||
| 7 | + .bar { | ||
| 8 | + float: left; | ||
| 9 | + height: 100%; | ||
| 10 | + } | ||
| 11 | + .bar-success { | ||
| 12 | + @include linear-gradient(#62C462, #51A351); | ||
| 13 | + background-color: #468847; | ||
| 14 | + } | ||
| 15 | + .bar-danger { | ||
| 16 | + @include linear-gradient(#EE5F5B, #BD362F); | ||
| 17 | + background-color: #B94A48; | ||
| 18 | + } | ||
| 19 | + } | ||
| 20 | + .upvotes { | ||
| 21 | + display: inline-block; | ||
| 22 | + color: #468847; | ||
| 23 | + } | ||
| 24 | + .downvotes { | ||
| 25 | + display: inline-block; | ||
| 26 | + color: #B94A48; | ||
| 27 | + } | ||
| 28 | +} | ||
| 29 | +.votes-block { | ||
| 30 | + margin: 14px 6px 6px 0; | ||
| 31 | + .downvotes { | ||
| 32 | + float: right; | ||
| 33 | + } | ||
| 34 | +} | ||
| 35 | +.votes-inline { | ||
| 36 | + display: inline-block; | ||
| 37 | + margin: 0 8px; | ||
| 38 | + .progress { | ||
| 39 | + display: inline-block; | ||
| 40 | + padding: 0 0 2px; | ||
| 41 | + width: 45px; | ||
| 42 | + } | ||
| 43 | +} |
app/assets/stylesheets/themes/ui_basic.scss
| @@ -4,18 +4,6 @@ | @@ -4,18 +4,6 @@ | ||
| 4 | * | 4 | * |
| 5 | */ | 5 | */ |
| 6 | .ui_basic { | 6 | .ui_basic { |
| 7 | - /* | ||
| 8 | - * Common styles | ||
| 9 | - * | ||
| 10 | - */ | ||
| 11 | - a { | ||
| 12 | - color: $link_color; | ||
| 13 | - &:hover { | ||
| 14 | - text-decoration: none; | ||
| 15 | - color: $primary_color; | ||
| 16 | - } | ||
| 17 | - } | ||
| 18 | - | ||
| 19 | .app_logo { | 7 | .app_logo { |
| 20 | .separator { | 8 | .separator { |
| 21 | margin-left: 0; | 9 | margin-left: 0; |
app/assets/stylesheets/variables.scss
app/contexts/project_update_context.rb
| @@ -2,7 +2,9 @@ class ProjectUpdateContext < BaseContext | @@ -2,7 +2,9 @@ class ProjectUpdateContext < BaseContext | ||
| 2 | def execute(role = :default) | 2 | def execute(role = :default) |
| 3 | namespace_id = params[:project].delete(:namespace_id) | 3 | namespace_id = params[:project].delete(:namespace_id) |
| 4 | 4 | ||
| 5 | - if namespace_id.present? | 5 | + allowed_transfer = can?(current_user, :change_namespace, project) || role == :admin |
| 6 | + | ||
| 7 | + if allowed_transfer && namespace_id.present? | ||
| 6 | if namespace_id == Namespace.global_id | 8 | if namespace_id == Namespace.global_id |
| 7 | if project.namespace.present? | 9 | if project.namespace.present? |
| 8 | # Transfer to global namespace from anyone | 10 | # Transfer to global namespace from anyone |
app/controllers/admin/groups_controller.rb
| @@ -2,7 +2,7 @@ class Admin::GroupsController < AdminController | @@ -2,7 +2,7 @@ class Admin::GroupsController < AdminController | ||
| 2 | before_filter :group, only: [:edit, :show, :update, :destroy, :project_update] | 2 | before_filter :group, only: [:edit, :show, :update, :destroy, :project_update] |
| 3 | 3 | ||
| 4 | def index | 4 | def index |
| 5 | - @groups = Group.scoped | 5 | + @groups = Group.order('name ASC') |
| 6 | @groups = @groups.search(params[:name]) if params[:name].present? | 6 | @groups = @groups.search(params[:name]) if params[:name].present? |
| 7 | @groups = @groups.page(params[:page]).per(20) | 7 | @groups = @groups.page(params[:page]).per(20) |
| 8 | end | 8 | end |
| @@ -11,6 +11,7 @@ class Admin::GroupsController < AdminController | @@ -11,6 +11,7 @@ class Admin::GroupsController < AdminController | ||
| 11 | @projects = Project.scoped | 11 | @projects = Project.scoped |
| 12 | @projects = @projects.not_in_group(@group) if @group.projects.present? | 12 | @projects = @projects.not_in_group(@group) if @group.projects.present? |
| 13 | @projects = @projects.all | 13 | @projects = @projects.all |
| 14 | + @projects.reject!(&:empty_repo?) | ||
| 14 | end | 15 | end |
| 15 | 16 | ||
| 16 | def new | 17 | def new |
app/controllers/admin/projects_controller.rb
| @@ -4,12 +4,13 @@ class Admin::ProjectsController < AdminController | @@ -4,12 +4,13 @@ class Admin::ProjectsController < AdminController | ||
| 4 | def index | 4 | def index |
| 5 | @projects = Project.scoped | 5 | @projects = Project.scoped |
| 6 | @projects = @projects.where(namespace_id: params[:namespace_id]) if params[:namespace_id].present? | 6 | @projects = @projects.where(namespace_id: params[:namespace_id]) if params[:namespace_id].present? |
| 7 | + @projects = @projects.where(namespace_id: nil) if params[:namespace_id] == Namespace.global_id | ||
| 7 | @projects = @projects.search(params[:name]) if params[:name].present? | 8 | @projects = @projects.search(params[:name]) if params[:name].present? |
| 8 | @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20) | 9 | @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20) |
| 9 | end | 10 | end |
| 10 | 11 | ||
| 11 | def show | 12 | def show |
| 12 | - @users = User.scoped | 13 | + @users = User.active |
| 13 | @users = @users.not_in_project(@project) if @project.users.present? | 14 | @users = @users.not_in_project(@project) if @project.users.present? |
| 14 | @users = @users.all | 15 | @users = @users.all |
| 15 | end | 16 | end |
app/controllers/admin/users_controller.rb
| @@ -3,7 +3,7 @@ class Admin::UsersController < AdminController | @@ -3,7 +3,7 @@ class Admin::UsersController < AdminController | ||
| 3 | @admin_users = User.scoped | 3 | @admin_users = User.scoped |
| 4 | @admin_users = @admin_users.filter(params[:filter]) | 4 | @admin_users = @admin_users.filter(params[:filter]) |
| 5 | @admin_users = @admin_users.search(params[:name]) if params[:name].present? | 5 | @admin_users = @admin_users.search(params[:name]) if params[:name].present? |
| 6 | - @admin_users = @admin_users.order("updated_at DESC").page(params[:page]) | 6 | + @admin_users = @admin_users.order("name ASC").page(params[:page]) |
| 7 | end | 7 | end |
| 8 | 8 | ||
| 9 | def show | 9 | def show |
| @@ -30,7 +30,7 @@ class Admin::UsersController < AdminController | @@ -30,7 +30,7 @@ class Admin::UsersController < AdminController | ||
| 30 | 30 | ||
| 31 | 31 | ||
| 32 | def new | 32 | def new |
| 33 | - @admin_user = User.new({ projects_limit: Gitlab.config.default_projects_limit }, as: :admin) | 33 | + @admin_user = User.new({ projects_limit: Gitlab.config.gitlab.default_projects_limit }, as: :admin) |
| 34 | end | 34 | end |
| 35 | 35 | ||
| 36 | def edit | 36 | def edit |
app/controllers/application_controller.rb
| @@ -112,6 +112,10 @@ class ApplicationController < ActionController::Base | @@ -112,6 +112,10 @@ class ApplicationController < ActionController::Base | ||
| 112 | render file: Rails.root.join("public", "404"), layout: false, status: "404" | 112 | render file: Rails.root.join("public", "404"), layout: false, status: "404" |
| 113 | end | 113 | end |
| 114 | 114 | ||
| 115 | + def render_403 | ||
| 116 | + render file: Rails.root.join("public", "403"), layout: false, status: "403" | ||
| 117 | + end | ||
| 118 | + | ||
| 115 | def require_non_empty_project | 119 | def require_non_empty_project |
| 116 | redirect_to @project if @project.empty_repo? | 120 | redirect_to @project if @project.empty_repo? |
| 117 | end | 121 | end |
app/controllers/dashboard_controller.rb
| @@ -7,6 +7,8 @@ class DashboardController < ApplicationController | @@ -7,6 +7,8 @@ class DashboardController < ApplicationController | ||
| 7 | def index | 7 | def index |
| 8 | @groups = current_user.authorized_groups | 8 | @groups = current_user.authorized_groups |
| 9 | 9 | ||
| 10 | + @has_authorized_projects = @projects.count > 0 | ||
| 11 | + | ||
| 10 | @projects = case params[:scope] | 12 | @projects = case params[:scope] |
| 11 | when 'personal' then | 13 | when 'personal' then |
| 12 | @projects.personal(current_user) | 14 | @projects.personal(current_user) |
app/controllers/groups_controller.rb
| @@ -21,7 +21,7 @@ class GroupsController < ApplicationController | @@ -21,7 +21,7 @@ class GroupsController < ApplicationController | ||
| 21 | 21 | ||
| 22 | # Get authored or assigned open merge requests | 22 | # Get authored or assigned open merge requests |
| 23 | def merge_requests | 23 | def merge_requests |
| 24 | - @merge_requests = current_user.cared_merge_requests | 24 | + @merge_requests = current_user.cared_merge_requests.opened |
| 25 | @merge_requests = @merge_requests.of_group(@group).recent.page(params[:page]).per(20) | 25 | @merge_requests = @merge_requests.of_group(@group).recent.page(params[:page]).per(20) |
| 26 | end | 26 | end |
| 27 | 27 | ||
| @@ -49,6 +49,7 @@ class GroupsController < ApplicationController | @@ -49,6 +49,7 @@ class GroupsController < ApplicationController | ||
| 49 | def people | 49 | def people |
| 50 | @project = group.projects.find(params[:project_id]) if params[:project_id] | 50 | @project = group.projects.find(params[:project_id]) if params[:project_id] |
| 51 | @users = @project ? @project.users : group.users | 51 | @users = @project ? @project.users : group.users |
| 52 | + @users.sort_by!(&:name) | ||
| 52 | 53 | ||
| 53 | if @project | 54 | if @project |
| 54 | @team_member = @project.users_projects.new | 55 | @team_member = @project.users_projects.new |
app/controllers/issues_controller.rb
| 1 | class IssuesController < ProjectResourceController | 1 | class IssuesController < ProjectResourceController |
| 2 | before_filter :module_enabled | 2 | before_filter :module_enabled |
| 3 | - before_filter :issue, only: [:edit, :update, :destroy, :show] | 3 | + before_filter :issue, only: [:edit, :update, :show] |
| 4 | 4 | ||
| 5 | # Allow read any issue | 5 | # Allow read any issue |
| 6 | before_filter :authorize_read_issue! | 6 | before_filter :authorize_read_issue! |
| @@ -11,9 +11,6 @@ class IssuesController < ProjectResourceController | @@ -11,9 +11,6 @@ class IssuesController < ProjectResourceController | ||
| 11 | # Allow modify issue | 11 | # Allow modify issue |
| 12 | before_filter :authorize_modify_issue!, only: [:edit, :update] | 12 | before_filter :authorize_modify_issue!, only: [:edit, :update] |
| 13 | 13 | ||
| 14 | - # Allow destroy issue | ||
| 15 | - before_filter :authorize_admin_issue!, only: [:destroy] | ||
| 16 | - | ||
| 17 | respond_to :js, :html | 14 | respond_to :js, :html |
| 18 | 15 | ||
| 19 | def index | 16 | def index |
| @@ -79,15 +76,6 @@ class IssuesController < ProjectResourceController | @@ -79,15 +76,6 @@ class IssuesController < ProjectResourceController | ||
| 79 | end | 76 | end |
| 80 | end | 77 | end |
| 81 | 78 | ||
| 82 | - def destroy | ||
| 83 | - @issue.destroy | ||
| 84 | - | ||
| 85 | - respond_to do |format| | ||
| 86 | - format.html { redirect_to project_issues_path } | ||
| 87 | - format.js { render nothing: true } | ||
| 88 | - end | ||
| 89 | - end | ||
| 90 | - | ||
| 91 | def sort | 79 | def sort |
| 92 | return render_404 unless can?(current_user, :admin_issue, @project) | 80 | return render_404 unless can?(current_user, :admin_issue, @project) |
| 93 | 81 |
app/controllers/merge_requests_controller.rb
| 1 | class MergeRequestsController < ProjectResourceController | 1 | class MergeRequestsController < ProjectResourceController |
| 2 | before_filter :module_enabled | 2 | before_filter :module_enabled |
| 3 | - before_filter :merge_request, only: [:edit, :update, :destroy, :show, :commits, :diffs, :automerge, :automerge_check] | 3 | + before_filter :merge_request, only: [:edit, :update, :show, :commits, :diffs, :automerge, :automerge_check, :ci_status] |
| 4 | before_filter :validates_merge_request, only: [:show, :diffs] | 4 | before_filter :validates_merge_request, only: [:show, :diffs] |
| 5 | before_filter :define_show_vars, only: [:show, :diffs] | 5 | before_filter :define_show_vars, only: [:show, :diffs] |
| 6 | 6 | ||
| @@ -13,9 +13,6 @@ class MergeRequestsController < ProjectResourceController | @@ -13,9 +13,6 @@ class MergeRequestsController < ProjectResourceController | ||
| 13 | # Allow modify merge_request | 13 | # Allow modify merge_request |
| 14 | before_filter :authorize_modify_merge_request!, only: [:close, :edit, :update, :sort] | 14 | before_filter :authorize_modify_merge_request!, only: [:close, :edit, :update, :sort] |
| 15 | 15 | ||
| 16 | - # Allow destroy merge_request | ||
| 17 | - before_filter :authorize_admin_merge_request!, only: [:destroy] | ||
| 18 | - | ||
| 19 | def index | 16 | def index |
| 20 | @merge_requests = MergeRequestsLoadContext.new(project, current_user, params).execute | 17 | @merge_requests = MergeRequestsLoadContext.new(project, current_user, params).execute |
| 21 | end | 18 | end |
| @@ -90,14 +87,6 @@ class MergeRequestsController < ProjectResourceController | @@ -90,14 +87,6 @@ class MergeRequestsController < ProjectResourceController | ||
| 90 | end | 87 | end |
| 91 | end | 88 | end |
| 92 | 89 | ||
| 93 | - def destroy | ||
| 94 | - @merge_request.destroy | ||
| 95 | - | ||
| 96 | - respond_to do |format| | ||
| 97 | - format.html { redirect_to project_merge_requests_url(@project) } | ||
| 98 | - end | ||
| 99 | - end | ||
| 100 | - | ||
| 101 | def branch_from | 90 | def branch_from |
| 102 | @commit = project.commit(params[:ref]) | 91 | @commit = project.commit(params[:ref]) |
| 103 | @commit = CommitDecorator.decorate(@commit) | 92 | @commit = CommitDecorator.decorate(@commit) |
| @@ -108,6 +97,13 @@ class MergeRequestsController < ProjectResourceController | @@ -108,6 +97,13 @@ class MergeRequestsController < ProjectResourceController | ||
| 108 | @commit = CommitDecorator.decorate(@commit) | 97 | @commit = CommitDecorator.decorate(@commit) |
| 109 | end | 98 | end |
| 110 | 99 | ||
| 100 | + def ci_status | ||
| 101 | + status = project.gitlab_ci_service.commit_status(merge_request.last_commit.sha) | ||
| 102 | + response = { status: status } | ||
| 103 | + | ||
| 104 | + render json: response | ||
| 105 | + end | ||
| 106 | + | ||
| 111 | protected | 107 | protected |
| 112 | 108 | ||
| 113 | def merge_request | 109 | def merge_request |
app/controllers/milestones_controller.rb
| @@ -12,11 +12,12 @@ class MilestonesController < ProjectResourceController | @@ -12,11 +12,12 @@ class MilestonesController < ProjectResourceController | ||
| 12 | 12 | ||
| 13 | def index | 13 | def index |
| 14 | @milestones = case params[:f] | 14 | @milestones = case params[:f] |
| 15 | - when 'all'; @project.milestones | ||
| 16 | - else @project.milestones.active | 15 | + when 'all'; @project.milestones.order("closed, due_date DESC") |
| 16 | + when 'closed'; @project.milestones.closed.order("due_date DESC") | ||
| 17 | + else @project.milestones.active.order("due_date ASC") | ||
| 17 | end | 18 | end |
| 18 | 19 | ||
| 19 | - @milestones = @milestones.includes(:project).order("due_date") | 20 | + @milestones = @milestones.includes(:project) |
| 20 | @milestones = @milestones.page(params[:page]).per(20) | 21 | @milestones = @milestones.page(params[:page]).per(20) |
| 21 | end | 22 | end |
| 22 | 23 | ||
| @@ -42,6 +43,7 @@ class MilestonesController < ProjectResourceController | @@ -42,6 +43,7 @@ class MilestonesController < ProjectResourceController | ||
| 42 | 43 | ||
| 43 | def create | 44 | def create |
| 44 | @milestone = @project.milestones.new(params[:milestone]) | 45 | @milestone = @project.milestones.new(params[:milestone]) |
| 46 | + @milestone.author_id_of_changes = current_user.id | ||
| 45 | 47 | ||
| 46 | if @milestone.save | 48 | if @milestone.save |
| 47 | redirect_to project_milestone_path(@project, @milestone) | 49 | redirect_to project_milestone_path(@project, @milestone) |
| @@ -51,7 +53,7 @@ class MilestonesController < ProjectResourceController | @@ -51,7 +53,7 @@ class MilestonesController < ProjectResourceController | ||
| 51 | end | 53 | end |
| 52 | 54 | ||
| 53 | def update | 55 | def update |
| 54 | - @milestone.update_attributes(params[:milestone]) | 56 | + @milestone.update_attributes(params[:milestone].merge(author_id_of_changes: current_user.id)) |
| 55 | 57 | ||
| 56 | respond_to do |format| | 58 | respond_to do |format| |
| 57 | format.js | 59 | format.js |
app/controllers/omniauth_callbacks_controller.rb
| 1 | class OmniauthCallbacksController < Devise::OmniauthCallbacksController | 1 | class OmniauthCallbacksController < Devise::OmniauthCallbacksController |
| 2 | - Gitlab.config.omniauth_providers.each do |provider| | 2 | + Gitlab.config.omniauth.providers.each do |provider| |
| 3 | define_method provider['name'] do | 3 | define_method provider['name'] do |
| 4 | handle_omniauth | 4 | handle_omniauth |
| 5 | end | 5 | end |
app/controllers/projects_controller.rb
| @@ -46,6 +46,10 @@ class ProjectsController < ProjectResourceController | @@ -46,6 +46,10 @@ class ProjectsController < ProjectResourceController | ||
| 46 | format.js | 46 | format.js |
| 47 | end | 47 | end |
| 48 | end | 48 | end |
| 49 | + | ||
| 50 | + rescue Project::TransferError => ex | ||
| 51 | + @error = ex | ||
| 52 | + render :update_failed | ||
| 49 | end | 53 | end |
| 50 | 54 | ||
| 51 | def show | 55 | def show |
| @@ -54,12 +58,12 @@ class ProjectsController < ProjectResourceController | @@ -54,12 +58,12 @@ class ProjectsController < ProjectResourceController | ||
| 54 | 58 | ||
| 55 | respond_to do |format| | 59 | respond_to do |format| |
| 56 | format.html do | 60 | format.html do |
| 57 | - unless @project.empty_repo? | ||
| 58 | - @last_push = current_user.recent_push(@project.id) | ||
| 59 | - render :show | ||
| 60 | - else | ||
| 61 | - render "projects/empty" | ||
| 62 | - end | 61 | + unless @project.empty_repo? |
| 62 | + @last_push = current_user.recent_push(@project.id) | ||
| 63 | + render :show | ||
| 64 | + else | ||
| 65 | + render "projects/empty" | ||
| 66 | + end | ||
| 63 | end | 67 | end |
| 64 | format.js | 68 | format.js |
| 65 | end | 69 | end |
| @@ -86,12 +90,18 @@ class ProjectsController < ProjectResourceController | @@ -86,12 +90,18 @@ class ProjectsController < ProjectResourceController | ||
| 86 | end | 90 | end |
| 87 | 91 | ||
| 88 | def graph | 92 | def graph |
| 89 | - graph = Gitlab::Graph::JsonBuilder.new(project) | ||
| 90 | - | ||
| 91 | - @days_json, @commits_json = graph.days_json, graph.commits_json | 93 | + respond_to do |format| |
| 94 | + format.html | ||
| 95 | + format.json do | ||
| 96 | + graph = Gitlab::Graph::JsonBuilder.new(project) | ||
| 97 | + render :json => graph.to_json | ||
| 98 | + end | ||
| 99 | + end | ||
| 92 | end | 100 | end |
| 93 | 101 | ||
| 94 | def destroy | 102 | def destroy |
| 103 | + return access_denied! unless can?(current_user, :remove_project, project) | ||
| 104 | + | ||
| 95 | # Disable the UsersProject update_repository call, otherwise it will be | 105 | # Disable the UsersProject update_repository call, otherwise it will be |
| 96 | # called once for every person removed from the project | 106 | # called once for every person removed from the project |
| 97 | UsersProject.skip_callback(:destroy, :after, :update_repository) | 107 | UsersProject.skip_callback(:destroy, :after, :update_repository) |
app/controllers/snippets_controller.rb
| @@ -16,7 +16,7 @@ class SnippetsController < ProjectResourceController | @@ -16,7 +16,7 @@ class SnippetsController < ProjectResourceController | ||
| 16 | respond_to :html | 16 | respond_to :html |
| 17 | 17 | ||
| 18 | def index | 18 | def index |
| 19 | - @snippets = @project.snippets | 19 | + @snippets = @project.snippets.fresh |
| 20 | end | 20 | end |
| 21 | 21 | ||
| 22 | def new | 22 | def new |
| @@ -62,7 +62,7 @@ class SnippetsController < ProjectResourceController | @@ -62,7 +62,7 @@ class SnippetsController < ProjectResourceController | ||
| 62 | redirect_to project_snippets_path(@project) | 62 | redirect_to project_snippets_path(@project) |
| 63 | end | 63 | end |
| 64 | 64 | ||
| 65 | - def raw | 65 | + def raw |
| 66 | send_data( | 66 | send_data( |
| 67 | @snippet.content, | 67 | @snippet.content, |
| 68 | type: "text/plain", | 68 | type: "text/plain", |
app/decorators/commit_decorator.rb
| @@ -76,7 +76,7 @@ class CommitDecorator < ApplicationDecorator | @@ -76,7 +76,7 @@ class CommitDecorator < ApplicationDecorator | ||
| 76 | source_name = send "#{options[:source]}_name".to_sym | 76 | source_name = send "#{options[:source]}_name".to_sym |
| 77 | source_email = send "#{options[:source]}_email".to_sym | 77 | source_email = send "#{options[:source]}_email".to_sym |
| 78 | text = if options[:avatar] | 78 | text = if options[:avatar] |
| 79 | - avatar = h.image_tag h.gravatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size] | 79 | + avatar = h.image_tag h.gravatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "" |
| 80 | %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>} | 80 | %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>} |
| 81 | else | 81 | else |
| 82 | source_name | 82 | source_name |
app/helpers/application_helper.rb
| 1 | require 'digest/md5' | 1 | require 'digest/md5' |
| 2 | +require 'uri' | ||
| 2 | 3 | ||
| 3 | module ApplicationHelper | 4 | module ApplicationHelper |
| 4 | 5 | ||
| @@ -30,13 +31,15 @@ module ApplicationHelper | @@ -30,13 +31,15 @@ module ApplicationHelper | ||
| 30 | args.any? { |v| v.to_s.downcase == action_name } | 31 | args.any? { |v| v.to_s.downcase == action_name } |
| 31 | end | 32 | end |
| 32 | 33 | ||
| 33 | - def gravatar_icon(user_email = '', size = 40) | ||
| 34 | - if Gitlab.config.disable_gravatar? || user_email.blank? | 34 | + def gravatar_icon(user_email = '', size = nil) |
| 35 | + size = 40 if size.nil? || size <= 0 | ||
| 36 | + | ||
| 37 | + if !Gitlab.config.gravatar.enabled || user_email.blank? | ||
| 35 | 'no_avatar.png' | 38 | 'no_avatar.png' |
| 36 | else | 39 | else |
| 37 | - gravatar_prefix = request.ssl? ? "https://secure" : "http://www" | 40 | + gravatar_url = request.ssl? ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url |
| 38 | user_email.strip! | 41 | user_email.strip! |
| 39 | - "#{gravatar_prefix}.gravatar.com/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=mm" | 42 | + sprintf(gravatar_url, {:hash => Digest::MD5.hexdigest(user_email.downcase), :email => URI.escape(user_email), :size => size}) |
| 40 | end | 43 | end |
| 41 | end | 44 | end |
| 42 | 45 | ||
| @@ -45,7 +48,7 @@ module ApplicationHelper | @@ -45,7 +48,7 @@ module ApplicationHelper | ||
| 45 | end | 48 | end |
| 46 | 49 | ||
| 47 | def web_app_url | 50 | def web_app_url |
| 48 | - "#{request_protocol}://#{Gitlab.config.web_host}/" | 51 | + "#{request_protocol}://#{Gitlab.config.gitlab.host}/" |
| 49 | end | 52 | end |
| 50 | 53 | ||
| 51 | def last_commit(project) | 54 | def last_commit(project) |
| @@ -92,6 +95,7 @@ module ApplicationHelper | @@ -92,6 +95,7 @@ module ApplicationHelper | ||
| 92 | { label: "API Help", url: help_api_path }, | 95 | { label: "API Help", url: help_api_path }, |
| 93 | { label: "Markdown Help", url: help_markdown_path }, | 96 | { label: "Markdown Help", url: help_markdown_path }, |
| 94 | { label: "SSH Keys Help", url: help_ssh_path }, | 97 | { label: "SSH Keys Help", url: help_ssh_path }, |
| 98 | + { label: "Gitlab Rake Tasks Help", url: help_raketasks_path }, | ||
| 95 | ] | 99 | ] |
| 96 | 100 | ||
| 97 | project_nav = [] | 101 | project_nav = [] |
app/helpers/issues_helper.rb
| @@ -4,28 +4,6 @@ module IssuesHelper | @@ -4,28 +4,6 @@ module IssuesHelper | ||
| 4 | project_issues_path project, params | 4 | project_issues_path project, params |
| 5 | end | 5 | end |
| 6 | 6 | ||
| 7 | - def link_to_issue_assignee(issue) | ||
| 8 | - project = issue.project | ||
| 9 | - | ||
| 10 | - tm = project.team_member_by_id(issue.assignee_id) | ||
| 11 | - if tm | ||
| 12 | - link_to issue.assignee_name, project_team_member_path(project, tm), class: "author_link" | ||
| 13 | - else | ||
| 14 | - issue.assignee_name | ||
| 15 | - end | ||
| 16 | - end | ||
| 17 | - | ||
| 18 | - def link_to_issue_author(issue) | ||
| 19 | - project = issue.project | ||
| 20 | - | ||
| 21 | - tm = project.team_member_by_id(issue.author_id) | ||
| 22 | - if tm | ||
| 23 | - link_to issue.author_name, project_team_member_path(project, tm), class: "author_link" | ||
| 24 | - else | ||
| 25 | - issue.author_name | ||
| 26 | - end | ||
| 27 | - end | ||
| 28 | - | ||
| 29 | def issue_css_classes issue | 7 | def issue_css_classes issue |
| 30 | classes = "issue" | 8 | classes = "issue" |
| 31 | classes << " closed" if issue.closed | 9 | classes << " closed" if issue.closed |
| @@ -52,4 +30,14 @@ module IssuesHelper | @@ -52,4 +30,14 @@ module IssuesHelper | ||
| 52 | open: "open" | 30 | open: "open" |
| 53 | } | 31 | } |
| 54 | end | 32 | end |
| 33 | + | ||
| 34 | + def labels_autocomplete_source | ||
| 35 | + labels = @project.issues_labels.order('count DESC') | ||
| 36 | + labels = labels.map{ |l| { label: l.name, value: l.name } } | ||
| 37 | + labels.to_json | ||
| 38 | + end | ||
| 39 | + | ||
| 40 | + def issues_active_milestones | ||
| 41 | + @project.milestones.active.order("id desc").all | ||
| 42 | + end | ||
| 55 | end | 43 | end |
app/helpers/merge_requests_helper.rb
| 1 | module MergeRequestsHelper | 1 | module MergeRequestsHelper |
| 2 | - def link_to_merge_request_assignee(merge_request) | ||
| 3 | - project = merge_request.project | ||
| 4 | - | ||
| 5 | - tm = project.team_member_by_id(merge_request.assignee_id) | ||
| 6 | - if tm | ||
| 7 | - link_to merge_request.assignee_name, project_team_member_path(project, tm), class: "author_link" | ||
| 8 | - else | ||
| 9 | - merge_request.assignee_name | ||
| 10 | - end | ||
| 11 | - end | ||
| 12 | - | ||
| 13 | - def link_to_merge_request_author(merge_request) | ||
| 14 | - project = merge_request.project | ||
| 15 | - | ||
| 16 | - tm = project.team_member_by_id(merge_request.author_id) | ||
| 17 | - if tm | ||
| 18 | - link_to merge_request.author_name, project_team_member_path(project, tm), class: "author_link" | ||
| 19 | - else | ||
| 20 | - merge_request.author_name | ||
| 21 | - end | ||
| 22 | - end | ||
| 23 | - | ||
| 24 | def new_mr_path_from_push_event(event) | 2 | def new_mr_path_from_push_event(event) |
| 25 | new_project_merge_request_path( | 3 | new_project_merge_request_path( |
| 26 | event.project, | 4 | event.project, |
| @@ -39,7 +17,7 @@ module MergeRequestsHelper | @@ -39,7 +17,7 @@ module MergeRequestsHelper | ||
| 39 | classes | 17 | classes |
| 40 | end | 18 | end |
| 41 | 19 | ||
| 42 | - def ci_status_path | ||
| 43 | - @project.gitlab_ci_service.commit_badge_path(@merge_request.last_commit.sha) | 20 | + def ci_build_details_path merge_request |
| 21 | + merge_request.project.gitlab_ci_service.build_page(merge_request.last_commit.sha) | ||
| 44 | end | 22 | end |
| 45 | end | 23 | end |
app/helpers/projects_helper.rb
| @@ -8,11 +8,49 @@ module ProjectsHelper | @@ -8,11 +8,49 @@ module ProjectsHelper | ||
| 8 | end | 8 | end |
| 9 | 9 | ||
| 10 | def link_to_project project | 10 | def link_to_project project |
| 11 | - link_to project.name, project | 11 | + link_to project do |
| 12 | + title = content_tag(:strong, project.name) | ||
| 13 | + | ||
| 14 | + if project.namespace | ||
| 15 | + namespace = content_tag(:span, "#{project.namespace.human_name} / ", class: 'tiny') | ||
| 16 | + title = namespace + title | ||
| 17 | + end | ||
| 18 | + | ||
| 19 | + title | ||
| 20 | + end | ||
| 21 | + end | ||
| 22 | + | ||
| 23 | + def link_to_member(project, author) | ||
| 24 | + return "(deleted)" unless author | ||
| 25 | + | ||
| 26 | + # Build avatar image tag | ||
| 27 | + avatar = image_tag(gravatar_icon(author.try(:email)), width: 16, class: "lil_av") | ||
| 28 | + | ||
| 29 | + # Build name strong tag | ||
| 30 | + name = content_tag :strong, author.name, class: 'author' | ||
| 31 | + | ||
| 32 | + author_html = avatar + name | ||
| 33 | + | ||
| 34 | + tm = project.team_member_by_id(author) | ||
| 35 | + | ||
| 36 | + content_tag :span, class: 'member-link' do | ||
| 37 | + if tm | ||
| 38 | + link_to author_html, project_team_member_path(project, tm), class: "author_link" | ||
| 39 | + else | ||
| 40 | + author_html | ||
| 41 | + end | ||
| 42 | + end | ||
| 12 | end | 43 | end |
| 13 | 44 | ||
| 14 | def tm_path team_member | 45 | def tm_path team_member |
| 15 | project_team_member_path(@project, team_member) | 46 | project_team_member_path(@project, team_member) |
| 16 | end | 47 | end |
| 17 | -end | ||
| 18 | 48 | ||
| 49 | + def project_title project | ||
| 50 | + if project.group | ||
| 51 | + project.name_with_namespace | ||
| 52 | + else | ||
| 53 | + project.name | ||
| 54 | + end | ||
| 55 | + end | ||
| 56 | +end |
app/helpers/tab_helper.rb
| @@ -72,7 +72,7 @@ module TabHelper | @@ -72,7 +72,7 @@ module TabHelper | ||
| 72 | return "active" if current_page?(controller: "projects", action: action, id: @project) | 72 | return "active" if current_page?(controller: "projects", action: action, id: @project) |
| 73 | end | 73 | end |
| 74 | 74 | ||
| 75 | - if ['snippets', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name | 75 | + if ['snippets', 'services', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name |
| 76 | "active" | 76 | "active" |
| 77 | end | 77 | end |
| 78 | end | 78 | end |
app/mailers/notify.rb
| @@ -3,11 +3,11 @@ class Notify < ActionMailer::Base | @@ -3,11 +3,11 @@ class Notify < ActionMailer::Base | ||
| 3 | add_template_helper ApplicationHelper | 3 | add_template_helper ApplicationHelper |
| 4 | add_template_helper GitlabMarkdownHelper | 4 | add_template_helper GitlabMarkdownHelper |
| 5 | 5 | ||
| 6 | - default_url_options[:host] = Gitlab.config.web_host | ||
| 7 | - default_url_options[:protocol] = Gitlab.config.web_protocol | ||
| 8 | - default_url_options[:port] = Gitlab.config.web_port if Gitlab.config.web_custom_port? | 6 | + default_url_options[:host] = Gitlab.config.gitlab.host |
| 7 | + default_url_options[:protocol] = Gitlab.config.gitlab.protocol | ||
| 8 | + default_url_options[:port] = Gitlab.config.gitlab.port if Gitlab.config.gitlab_on_non_standard_port? | ||
| 9 | 9 | ||
| 10 | - default from: Gitlab.config.email_from | 10 | + default from: Gitlab.config.gitlab.email_from |
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | 13 | ||
| @@ -31,6 +31,7 @@ class Notify < ActionMailer::Base | @@ -31,6 +31,7 @@ class Notify < ActionMailer::Base | ||
| 31 | def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id) | 31 | def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id) |
| 32 | @issue = Issue.find issue_id | 32 | @issue = Issue.find issue_id |
| 33 | @issue_status = status | 33 | @issue_status = status |
| 34 | + @project = @issue.project | ||
| 34 | @updated_by = User.find updated_by_user_id | 35 | @updated_by = User.find updated_by_user_id |
| 35 | mail(to: recipient(recipient_id), | 36 | mail(to: recipient(recipient_id), |
| 36 | subject: subject("changed issue ##{@issue.id}", @issue.title)) | 37 | subject: subject("changed issue ##{@issue.id}", @issue.title)) |
| @@ -102,6 +103,12 @@ class Notify < ActionMailer::Base | @@ -102,6 +103,12 @@ class Notify < ActionMailer::Base | ||
| 102 | end | 103 | end |
| 103 | 104 | ||
| 104 | 105 | ||
| 106 | + def project_was_moved_email(user_project_id) | ||
| 107 | + @users_project = UsersProject.find user_project_id | ||
| 108 | + @project = @users_project.project | ||
| 109 | + mail(to: @users_project.user.email, | ||
| 110 | + subject: subject("project was moved")) | ||
| 111 | + end | ||
| 105 | 112 | ||
| 106 | # | 113 | # |
| 107 | # User | 114 | # User |
app/models/ability.rb
| @@ -17,9 +17,7 @@ class Ability | @@ -17,9 +17,7 @@ class Ability | ||
| 17 | 17 | ||
| 18 | # Rules based on role in project | 18 | # Rules based on role in project |
| 19 | if project.master_access_for?(user) | 19 | if project.master_access_for?(user) |
| 20 | - # TODO: replace with master rules. | ||
| 21 | - # Only allow project administration for namespace owners | ||
| 22 | - rules << project_admin_rules | 20 | + rules << project_master_rules |
| 23 | 21 | ||
| 24 | elsif project.dev_access_for?(user) | 22 | elsif project.dev_access_for?(user) |
| 25 | rules << project_dev_rules | 23 | rules << project_dev_rules |
| @@ -93,13 +91,16 @@ class Ability | @@ -93,13 +91,16 @@ class Ability | ||
| 93 | :admin_merge_request, | 91 | :admin_merge_request, |
| 94 | :admin_note, | 92 | :admin_note, |
| 95 | :accept_mr, | 93 | :accept_mr, |
| 96 | - :admin_wiki | 94 | + :admin_wiki, |
| 95 | + :admin_project | ||
| 97 | ] | 96 | ] |
| 98 | end | 97 | end |
| 99 | 98 | ||
| 100 | def project_admin_rules | 99 | def project_admin_rules |
| 101 | project_master_rules + [ | 100 | project_master_rules + [ |
| 102 | - :admin_project | 101 | + :change_namespace, |
| 102 | + :rename_project, | ||
| 103 | + :remove_project | ||
| 103 | ] | 104 | ] |
| 104 | end | 105 | end |
| 105 | 106 |
app/models/commit.rb
| @@ -87,14 +87,10 @@ class Commit | @@ -87,14 +87,10 @@ class Commit | ||
| 87 | last = project.commit(from.try(:strip)) | 87 | last = project.commit(from.try(:strip)) |
| 88 | 88 | ||
| 89 | if first && last | 89 | if first && last |
| 90 | - commits = [first, last].sort_by(&:created_at) | ||
| 91 | - younger = commits.first | ||
| 92 | - older = commits.last | ||
| 93 | - | ||
| 94 | - result[:same] = (younger.id == older.id) | ||
| 95 | - result[:commits] = project.repo.commits_between(younger.id, older.id).map {|c| Commit.new(c)} | ||
| 96 | - result[:diffs] = project.repo.diff(younger.id, older.id) rescue [] | ||
| 97 | - result[:commit] = Commit.new(older) | 90 | + result[:same] = (first.id == last.id) |
| 91 | + result[:commits] = project.repo.commits_between(last.id, first.id).map {|c| Commit.new(c)} | ||
| 92 | + result[:diffs] = project.repo.diff(last.id, first.id) rescue [] | ||
| 93 | + result[:commit] = Commit.new(first) | ||
| 98 | end | 94 | end |
| 99 | 95 | ||
| 100 | result | 96 | result |
| @@ -163,6 +159,8 @@ class Commit | @@ -163,6 +159,8 @@ class Commit | ||
| 163 | while !lines.first.start_with?("diff --git") do | 159 | while !lines.first.start_with?("diff --git") do |
| 164 | lines.shift | 160 | lines.shift |
| 165 | end | 161 | end |
| 162 | + lines.pop if lines.last =~ /^[\d.]+$/ # Git version | ||
| 163 | + lines.pop if lines.last == "-- " # end of diff | ||
| 166 | lines.join("\n") | 164 | lines.join("\n") |
| 167 | end | 165 | end |
| 168 | end | 166 | end |
app/models/event.rb
| @@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
| 15 | # | 15 | # |
| 16 | 16 | ||
| 17 | class Event < ActiveRecord::Base | 17 | class Event < ActiveRecord::Base |
| 18 | + include NoteEvent | ||
| 18 | include PushEvent | 19 | include PushEvent |
| 19 | 20 | ||
| 20 | attr_accessible :project, :action, :data, :author_id, :project_id, | 21 | attr_accessible :project, :action, :data, :author_id, :project_id, |
| @@ -58,12 +59,14 @@ class Event < ActiveRecord::Base | @@ -58,12 +59,14 @@ class Event < ActiveRecord::Base | ||
| 58 | end | 59 | end |
| 59 | end | 60 | end |
| 60 | 61 | ||
| 61 | - # Next events currently enabled for system | ||
| 62 | - # - push | ||
| 63 | - # - new issue | ||
| 64 | - # - merge request | ||
| 65 | - def allowed? | ||
| 66 | - push? || issue? || merge_request? || membership_changed? | 62 | + def proper? |
| 63 | + if push? | ||
| 64 | + true | ||
| 65 | + elsif membership_changed? | ||
| 66 | + true | ||
| 67 | + else | ||
| 68 | + (issue? || merge_request? || note? || milestone?) && target | ||
| 69 | + end | ||
| 67 | end | 70 | end |
| 68 | 71 | ||
| 69 | def project_name | 72 | def project_name |
| @@ -94,6 +97,14 @@ class Event < ActiveRecord::Base | @@ -94,6 +97,14 @@ class Event < ActiveRecord::Base | ||
| 94 | action == self.class::Reopened | 97 | action == self.class::Reopened |
| 95 | end | 98 | end |
| 96 | 99 | ||
| 100 | + def milestone? | ||
| 101 | + target_type == "Milestone" | ||
| 102 | + end | ||
| 103 | + | ||
| 104 | + def note? | ||
| 105 | + target_type == "Note" | ||
| 106 | + end | ||
| 107 | + | ||
| 97 | def issue? | 108 | def issue? |
| 98 | target_type == "Issue" | 109 | target_type == "Issue" |
| 99 | end | 110 | end |
app/models/gitlab_ci_service.rb
| @@ -36,4 +36,22 @@ class GitlabCiService < Service | @@ -36,4 +36,22 @@ class GitlabCiService < Service | ||
| 36 | def commit_badge_path sha | 36 | def commit_badge_path sha |
| 37 | project_url + "/status?sha=#{sha}" | 37 | project_url + "/status?sha=#{sha}" |
| 38 | end | 38 | end |
| 39 | + | ||
| 40 | + def commit_status_path sha | ||
| 41 | + project_url + "/builds/#{sha}/status.json?token=#{token}" | ||
| 42 | + end | ||
| 43 | + | ||
| 44 | + def commit_status sha | ||
| 45 | + response = HTTParty.get(commit_status_path(sha)) | ||
| 46 | + | ||
| 47 | + if response.code == 200 and response["status"] | ||
| 48 | + response["status"] | ||
| 49 | + else | ||
| 50 | + :error | ||
| 51 | + end | ||
| 52 | + end | ||
| 53 | + | ||
| 54 | + def build_page sha | ||
| 55 | + project_url + "/builds/#{sha}" | ||
| 56 | + end | ||
| 39 | end | 57 | end |
app/models/merge_request.rb
| @@ -204,7 +204,7 @@ class MergeRequest < ActiveRecord::Base | @@ -204,7 +204,7 @@ class MergeRequest < ActiveRecord::Base | ||
| 204 | 204 | ||
| 205 | def mr_and_commit_notes | 205 | def mr_and_commit_notes |
| 206 | commit_ids = commits.map(&:id) | 206 | commit_ids = commits.map(&:id) |
| 207 | - 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) | 207 | + 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) |
| 208 | end | 208 | end |
| 209 | 209 | ||
| 210 | # Returns the raw diff for this merge request | 210 | # Returns the raw diff for this merge request |
| @@ -220,4 +220,8 @@ class MergeRequest < ActiveRecord::Base | @@ -220,4 +220,8 @@ class MergeRequest < ActiveRecord::Base | ||
| 220 | def to_patch | 220 | def to_patch |
| 221 | project.repo.git.format_patch({timeout: 30, raise: true, stdout: true}, "#{target_branch}..#{source_branch}") | 221 | project.repo.git.format_patch({timeout: 30, raise: true, stdout: true}, "#{target_branch}..#{source_branch}") |
| 222 | end | 222 | end |
| 223 | + | ||
| 224 | + def last_commit_short_sha | ||
| 225 | + @last_commit_short_sha ||= last_commit.sha[0..10] | ||
| 226 | + end | ||
| 223 | end | 227 | end |
app/models/milestone.rb
| @@ -13,18 +13,26 @@ | @@ -13,18 +13,26 @@ | ||
| 13 | # | 13 | # |
| 14 | 14 | ||
| 15 | class Milestone < ActiveRecord::Base | 15 | class Milestone < ActiveRecord::Base |
| 16 | - attr_accessible :title, :description, :due_date, :closed | 16 | + attr_accessible :title, :description, :due_date, :closed, :author_id_of_changes |
| 17 | + attr_accessor :author_id_of_changes | ||
| 17 | 18 | ||
| 18 | belongs_to :project | 19 | belongs_to :project |
| 19 | has_many :issues | 20 | has_many :issues |
| 20 | has_many :merge_requests | 21 | has_many :merge_requests |
| 21 | 22 | ||
| 23 | + scope :active, where(closed: false) | ||
| 24 | + scope :closed, where(closed: true) | ||
| 25 | + | ||
| 22 | validates :title, presence: true | 26 | validates :title, presence: true |
| 23 | validates :project, presence: true | 27 | validates :project, presence: true |
| 24 | validates :closed, inclusion: { in: [true, false] } | 28 | validates :closed, inclusion: { in: [true, false] } |
| 25 | 29 | ||
| 26 | - def self.active | ||
| 27 | - where("due_date > ? OR due_date IS NULL", Date.today) | 30 | + def expired? |
| 31 | + if due_date | ||
| 32 | + due_date < Date.today | ||
| 33 | + else | ||
| 34 | + false | ||
| 35 | + end | ||
| 28 | end | 36 | end |
| 29 | 37 | ||
| 30 | def participants | 38 | def participants |
| @@ -52,4 +60,20 @@ class Milestone < ActiveRecord::Base | @@ -52,4 +60,20 @@ class Milestone < ActiveRecord::Base | ||
| 52 | def expires_at | 60 | def expires_at |
| 53 | "expires at #{due_date.stamp("Aug 21, 2011")}" if due_date | 61 | "expires at #{due_date.stamp("Aug 21, 2011")}" if due_date |
| 54 | end | 62 | end |
| 63 | + | ||
| 64 | + def can_be_closed? | ||
| 65 | + open? && issues.opened.count.zero? | ||
| 66 | + end | ||
| 67 | + | ||
| 68 | + def is_empty? | ||
| 69 | + total_items_count.zero? | ||
| 70 | + end | ||
| 71 | + | ||
| 72 | + def open? | ||
| 73 | + !closed | ||
| 74 | + end | ||
| 75 | + | ||
| 76 | + def author_id | ||
| 77 | + author_id_of_changes | ||
| 78 | + end | ||
| 55 | end | 79 | end |
app/models/namespace.rb
| @@ -48,23 +48,30 @@ class Namespace < ActiveRecord::Base | @@ -48,23 +48,30 @@ class Namespace < ActiveRecord::Base | ||
| 48 | end | 48 | end |
| 49 | 49 | ||
| 50 | def ensure_dir_exist | 50 | def ensure_dir_exist |
| 51 | - namespace_dir_path = File.join(Gitlab.config.git_base_path, path) | 51 | + namespace_dir_path = File.join(Gitlab.config.gitolite.repos_path, path) |
| 52 | system("mkdir -m 770 #{namespace_dir_path}") unless File.exists?(namespace_dir_path) | 52 | system("mkdir -m 770 #{namespace_dir_path}") unless File.exists?(namespace_dir_path) |
| 53 | end | 53 | end |
| 54 | 54 | ||
| 55 | def move_dir | 55 | def move_dir |
| 56 | if path_changed? | 56 | if path_changed? |
| 57 | - old_path = File.join(Gitlab.config.git_base_path, path_was) | ||
| 58 | - new_path = File.join(Gitlab.config.git_base_path, path) | 57 | + old_path = File.join(Gitlab.config.gitolite.repos_path, path_was) |
| 58 | + new_path = File.join(Gitlab.config.gitolite.repos_path, path) | ||
| 59 | if File.exists?(new_path) | 59 | if File.exists?(new_path) |
| 60 | raise "Already exists" | 60 | raise "Already exists" |
| 61 | end | 61 | end |
| 62 | - system("mv #{old_path} #{new_path}") | 62 | + |
| 63 | + if system("mv #{old_path} #{new_path}") | ||
| 64 | + send_update_instructions | ||
| 65 | + end | ||
| 63 | end | 66 | end |
| 64 | end | 67 | end |
| 65 | 68 | ||
| 66 | def rm_dir | 69 | def rm_dir |
| 67 | - dir_path = File.join(Gitlab.config.git_base_path, path) | 70 | + dir_path = File.join(Gitlab.config.gitolite.repos_path, path) |
| 68 | system("rm -rf #{dir_path}") | 71 | system("rm -rf #{dir_path}") |
| 69 | end | 72 | end |
| 73 | + | ||
| 74 | + def send_update_instructions | ||
| 75 | + projects.each(&:send_move_instructions) | ||
| 76 | + end | ||
| 70 | end | 77 | end |
app/models/note.rb
| @@ -19,7 +19,7 @@ require 'file_size_validator' | @@ -19,7 +19,7 @@ require 'file_size_validator' | ||
| 19 | 19 | ||
| 20 | class Note < ActiveRecord::Base | 20 | class Note < ActiveRecord::Base |
| 21 | attr_accessible :note, :noteable, :noteable_id, :noteable_type, :project_id, | 21 | attr_accessible :note, :noteable, :noteable_id, :noteable_type, :project_id, |
| 22 | - :attachment, :line_code | 22 | + :attachment, :line_code, :commit_id |
| 23 | 23 | ||
| 24 | attr_accessor :notify | 24 | attr_accessor :notify |
| 25 | attr_accessor :notify_author | 25 | attr_accessor :notify_author |
| @@ -35,10 +35,14 @@ class Note < ActiveRecord::Base | @@ -35,10 +35,14 @@ class Note < ActiveRecord::Base | ||
| 35 | validates :line_code, format: { with: /\A\d+_\d+_\d+\Z/ }, allow_blank: true | 35 | validates :line_code, format: { with: /\A\d+_\d+_\d+\Z/ }, allow_blank: true |
| 36 | validates :attachment, file_size: { maximum: 10.megabytes.to_i } | 36 | validates :attachment, file_size: { maximum: 10.megabytes.to_i } |
| 37 | 37 | ||
| 38 | + validates :noteable_id, presence: true, if: ->(n) { n.noteable_type.present? && n.noteable_type != 'Commit' } | ||
| 39 | + validates :commit_id, presence: true, if: ->(n) { n.noteable_type == 'Commit' } | ||
| 40 | + | ||
| 38 | mount_uploader :attachment, AttachmentUploader | 41 | mount_uploader :attachment, AttachmentUploader |
| 39 | 42 | ||
| 40 | # Scopes | 43 | # Scopes |
| 41 | - scope :common, ->{ where(noteable_id: nil) } | 44 | + scope :for_commits, ->{ where(noteable_type: "Commit") } |
| 45 | + scope :common, ->{ where(noteable_id: nil, commit_id: nil) } | ||
| 42 | scope :today, ->{ where("created_at >= :date", date: Date.today) } | 46 | scope :today, ->{ where("created_at >= :date", date: Date.today) } |
| 43 | scope :last_week, ->{ where("created_at >= :date", date: (Date.today - 7.days)) } | 47 | scope :last_week, ->{ where("created_at >= :date", date: (Date.today - 7.days)) } |
| 44 | scope :since, ->(day) { where("created_at >= :date", date: (day)) } | 48 | scope :since, ->(day) { where("created_at >= :date", date: (day)) } |
| @@ -122,7 +126,7 @@ class Note < ActiveRecord::Base | @@ -122,7 +126,7 @@ class Note < ActiveRecord::Base | ||
| 122 | # override to return commits, which are not active record | 126 | # override to return commits, which are not active record |
| 123 | def noteable | 127 | def noteable |
| 124 | if for_commit? | 128 | if for_commit? |
| 125 | - project.commit(noteable_id) | 129 | + project.commit(commit_id) |
| 126 | else | 130 | else |
| 127 | super | 131 | super |
| 128 | end | 132 | end |
| @@ -151,4 +155,12 @@ class Note < ActiveRecord::Base | @@ -151,4 +155,12 @@ class Note < ActiveRecord::Base | ||
| 151 | def votable? | 155 | def votable? |
| 152 | for_issue? || (for_merge_request? && !for_diff_line?) | 156 | for_issue? || (for_merge_request? && !for_diff_line?) |
| 153 | end | 157 | end |
| 158 | + | ||
| 159 | + def noteable_type_name | ||
| 160 | + if noteable_type.present? | ||
| 161 | + noteable_type.downcase | ||
| 162 | + else | ||
| 163 | + "wall" | ||
| 164 | + end | ||
| 165 | + end | ||
| 154 | end | 166 | end |
app/models/project.rb
| @@ -25,6 +25,9 @@ class Project < ActiveRecord::Base | @@ -25,6 +25,9 @@ class Project < ActiveRecord::Base | ||
| 25 | include PushObserver | 25 | include PushObserver |
| 26 | include Authority | 26 | include Authority |
| 27 | include Team | 27 | include Team |
| 28 | + include NamespacedProject | ||
| 29 | + | ||
| 30 | + class TransferError < StandardError; end | ||
| 28 | 31 | ||
| 29 | attr_accessible :name, :path, :description, :default_branch, :issues_enabled, | 32 | attr_accessible :name, :path, :description, :default_branch, :issues_enabled, |
| 30 | :wall_enabled, :merge_requests_enabled, :wiki_enabled, as: [:default, :admin] | 33 | :wall_enabled, :merge_requests_enabled, :wiki_enabled, as: [:default, :admin] |
| @@ -36,6 +39,10 @@ class Project < ActiveRecord::Base | @@ -36,6 +39,10 @@ class Project < ActiveRecord::Base | ||
| 36 | # Relations | 39 | # Relations |
| 37 | belongs_to :group, foreign_key: "namespace_id", conditions: "type = 'Group'" | 40 | belongs_to :group, foreign_key: "namespace_id", conditions: "type = 'Group'" |
| 38 | belongs_to :namespace | 41 | belongs_to :namespace |
| 42 | + | ||
| 43 | + # TODO: replace owner with creator. | ||
| 44 | + # With namespaces a project owner will be a namespace owner | ||
| 45 | + # so this field makes sense only for global projects | ||
| 39 | belongs_to :owner, class_name: "User" | 46 | belongs_to :owner, class_name: "User" |
| 40 | has_many :users, through: :users_projects | 47 | has_many :users, through: :users_projects |
| 41 | has_many :events, dependent: :destroy | 48 | has_many :events, dependent: :destroy |
| @@ -97,7 +104,7 @@ class Project < ActiveRecord::Base | @@ -97,7 +104,7 @@ class Project < ActiveRecord::Base | ||
| 97 | namespace_id = Namespace.find_by_path(id.first).id | 104 | namespace_id = Namespace.find_by_path(id.first).id |
| 98 | where(namespace_id: namespace_id).find_by_path(id.last) | 105 | where(namespace_id: namespace_id).find_by_path(id.last) |
| 99 | else | 106 | else |
| 100 | - find_by_path(id) | 107 | + where(path: id, namespace_id: nil).last |
| 101 | end | 108 | end |
| 102 | end | 109 | end |
| 103 | 110 | ||
| @@ -172,7 +179,7 @@ class Project < ActiveRecord::Base | @@ -172,7 +179,7 @@ class Project < ActiveRecord::Base | ||
| 172 | end | 179 | end |
| 173 | 180 | ||
| 174 | def repo_name | 181 | def repo_name |
| 175 | - denied_paths = %w(gitolite-admin groups projects dashboard) | 182 | + denied_paths = %w(gitolite-admin admin dashboard groups help profile projects search) |
| 176 | 183 | ||
| 177 | if denied_paths.include?(path) | 184 | if denied_paths.include?(path) |
| 178 | errors.add(:path, "like #{path} is not allowed") | 185 | errors.add(:path, "like #{path} is not allowed") |
| @@ -188,7 +195,7 @@ class Project < ActiveRecord::Base | @@ -188,7 +195,7 @@ class Project < ActiveRecord::Base | ||
| 188 | end | 195 | end |
| 189 | 196 | ||
| 190 | def web_url | 197 | def web_url |
| 191 | - [Gitlab.config.url, path].join("/") | 198 | + [Gitlab.config.gitlab.url, path_with_namespace].join("/") |
| 192 | end | 199 | end |
| 193 | 200 | ||
| 194 | def common_notes | 201 | def common_notes |
| @@ -196,15 +203,15 @@ class Project < ActiveRecord::Base | @@ -196,15 +203,15 @@ class Project < ActiveRecord::Base | ||
| 196 | end | 203 | end |
| 197 | 204 | ||
| 198 | def build_commit_note(commit) | 205 | def build_commit_note(commit) |
| 199 | - notes.new(noteable_id: commit.id, noteable_type: "Commit") | 206 | + notes.new(commit_id: commit.id, noteable_type: "Commit") |
| 200 | end | 207 | end |
| 201 | 208 | ||
| 202 | def commit_notes(commit) | 209 | def commit_notes(commit) |
| 203 | - notes.where(noteable_id: commit.id, noteable_type: "Commit").where('line_code IS NULL OR line_code = ""') | 210 | + notes.where(commit_id: commit.id, noteable_type: "Commit").where('line_code IS NULL OR line_code = ""') |
| 204 | end | 211 | end |
| 205 | 212 | ||
| 206 | def commit_line_notes(commit) | 213 | def commit_line_notes(commit) |
| 207 | - notes.where(noteable_id: commit.id, noteable_type: "Commit").where("line_code IS NOT NULL") | 214 | + notes.where(commit_id: commit.id, noteable_type: "Commit").where("line_code IS NOT NULL") |
| 208 | end | 215 | end |
| 209 | 216 | ||
| 210 | def public? | 217 | def public? |
| @@ -239,51 +246,11 @@ class Project < ActiveRecord::Base | @@ -239,51 +246,11 @@ class Project < ActiveRecord::Base | ||
| 239 | gitlab_ci_service && gitlab_ci_service.active | 246 | gitlab_ci_service && gitlab_ci_service.active |
| 240 | end | 247 | end |
| 241 | 248 | ||
| 242 | - def path_with_namespace | ||
| 243 | - if namespace | ||
| 244 | - namespace.path + '/' + path | ||
| 245 | - else | ||
| 246 | - path | ||
| 247 | - end | ||
| 248 | - end | ||
| 249 | - | ||
| 250 | # For compatibility with old code | 249 | # For compatibility with old code |
| 251 | def code | 250 | def code |
| 252 | path | 251 | path |
| 253 | end | 252 | end |
| 254 | 253 | ||
| 255 | - def transfer(new_namespace) | ||
| 256 | - Project.transaction do | ||
| 257 | - old_namespace = namespace | ||
| 258 | - self.namespace = new_namespace | ||
| 259 | - | ||
| 260 | - old_dir = old_namespace.try(:path) || '' | ||
| 261 | - new_dir = new_namespace.try(:path) || '' | ||
| 262 | - | ||
| 263 | - old_repo = if old_dir.present? | ||
| 264 | - File.join(old_dir, self.path) | ||
| 265 | - else | ||
| 266 | - self.path | ||
| 267 | - end | ||
| 268 | - | ||
| 269 | - Gitlab::ProjectMover.new(self, old_dir, new_dir).execute | ||
| 270 | - | ||
| 271 | - git_host.move_repository(old_repo, self) | ||
| 272 | - | ||
| 273 | - save! | ||
| 274 | - end | ||
| 275 | - end | ||
| 276 | - | ||
| 277 | - def name_with_namespace | ||
| 278 | - @name_with_namespace ||= begin | ||
| 279 | - if namespace | ||
| 280 | - namespace.human_name + " / " + name | ||
| 281 | - else | ||
| 282 | - name | ||
| 283 | - end | ||
| 284 | - end | ||
| 285 | - end | ||
| 286 | - | ||
| 287 | def items_for entity | 254 | def items_for entity |
| 288 | case entity | 255 | case entity |
| 289 | when 'issue' then | 256 | when 'issue' then |
| @@ -293,7 +260,9 @@ class Project < ActiveRecord::Base | @@ -293,7 +260,9 @@ class Project < ActiveRecord::Base | ||
| 293 | end | 260 | end |
| 294 | end | 261 | end |
| 295 | 262 | ||
| 296 | - def namespace_owner | ||
| 297 | - namespace.try(:owner) | 263 | + def send_move_instructions |
| 264 | + self.users_projects.each do |member| | ||
| 265 | + Notify.project_was_moved_email(member.id).deliver | ||
| 266 | + end | ||
| 298 | end | 267 | end |
| 299 | end | 268 | end |
app/models/snippet.rb
| @@ -22,7 +22,7 @@ class Snippet < ActiveRecord::Base | @@ -22,7 +22,7 @@ class Snippet < ActiveRecord::Base | ||
| 22 | belongs_to :author, class_name: "User" | 22 | belongs_to :author, class_name: "User" |
| 23 | has_many :notes, as: :noteable, dependent: :destroy | 23 | has_many :notes, as: :noteable, dependent: :destroy |
| 24 | 24 | ||
| 25 | - delegate :name, :email, to: :author, prefix: true | 25 | + delegate :name, :email, to: :author, prefix: true, allow_nil: true |
| 26 | 26 | ||
| 27 | validates :author, presence: true | 27 | validates :author, presence: true |
| 28 | validates :project, presence: true | 28 | validates :project, presence: true |
app/models/user.rb
| @@ -56,12 +56,12 @@ class User < ActiveRecord::Base | @@ -56,12 +56,12 @@ class User < ActiveRecord::Base | ||
| 56 | has_many :issues, foreign_key: :author_id, dependent: :destroy | 56 | has_many :issues, foreign_key: :author_id, dependent: :destroy |
| 57 | has_many :notes, foreign_key: :author_id, dependent: :destroy | 57 | has_many :notes, foreign_key: :author_id, dependent: :destroy |
| 58 | has_many :merge_requests, foreign_key: :author_id, dependent: :destroy | 58 | has_many :merge_requests, foreign_key: :author_id, dependent: :destroy |
| 59 | - has_many :my_own_projects, class_name: "Project", foreign_key: :owner_id | ||
| 60 | has_many :events, class_name: "Event", foreign_key: :author_id, dependent: :destroy | 59 | has_many :events, class_name: "Event", foreign_key: :author_id, dependent: :destroy |
| 61 | has_many :recent_events, class_name: "Event", foreign_key: :author_id, order: "id DESC" | 60 | has_many :recent_events, class_name: "Event", foreign_key: :author_id, order: "id DESC" |
| 62 | has_many :assigned_issues, class_name: "Issue", foreign_key: :assignee_id, dependent: :destroy | 61 | has_many :assigned_issues, class_name: "Issue", foreign_key: :assignee_id, dependent: :destroy |
| 63 | has_many :assigned_merge_requests, class_name: "MergeRequest", foreign_key: :assignee_id, dependent: :destroy | 62 | has_many :assigned_merge_requests, class_name: "MergeRequest", foreign_key: :assignee_id, dependent: :destroy |
| 64 | 63 | ||
| 64 | + validates :name, presence: true | ||
| 65 | validates :bio, length: { within: 0..255 } | 65 | validates :bio, length: { within: 0..255 } |
| 66 | validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider} | 66 | validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider} |
| 67 | validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0} | 67 | validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0} |
| @@ -123,16 +123,4 @@ class User < ActiveRecord::Base | @@ -123,16 +123,4 @@ class User < ActiveRecord::Base | ||
| 123 | self.password = self.password_confirmation = Devise.friendly_token.first(8) | 123 | self.password = self.password_confirmation = Devise.friendly_token.first(8) |
| 124 | end | 124 | end |
| 125 | end | 125 | end |
| 126 | - | ||
| 127 | - def authorized_groups | ||
| 128 | - @authorized_groups ||= begin | ||
| 129 | - groups = Group.where(id: self.projects.pluck(:namespace_id)).all | ||
| 130 | - groups = groups + self.groups | ||
| 131 | - groups.uniq | ||
| 132 | - end | ||
| 133 | - end | ||
| 134 | - | ||
| 135 | - def authorized_projects | ||
| 136 | - Project.authorized_for(self) | ||
| 137 | - end | ||
| 138 | end | 126 | end |
app/models/users_project.rb
| @@ -28,6 +28,7 @@ class UsersProject < ActiveRecord::Base | @@ -28,6 +28,7 @@ class UsersProject < ActiveRecord::Base | ||
| 28 | 28 | ||
| 29 | validates :user, presence: true | 29 | validates :user, presence: true |
| 30 | validates :user_id, uniqueness: { :scope => [:project_id], message: "already exists in project" } | 30 | validates :user_id, uniqueness: { :scope => [:project_id], message: "already exists in project" } |
| 31 | + validates :project_access, inclusion: { in: [GUEST, REPORTER, DEVELOPER, MASTER] }, presence: true | ||
| 31 | validates :project, presence: true | 32 | validates :project, presence: true |
| 32 | 33 | ||
| 33 | delegate :name, :email, to: :user, prefix: true | 34 | delegate :name, :email, to: :user, prefix: true |
app/observers/activity_observer.rb
| 1 | class ActivityObserver < ActiveRecord::Observer | 1 | class ActivityObserver < ActiveRecord::Observer |
| 2 | - observe :issue, :merge_request | 2 | + observe :issue, :merge_request, :note, :milestone |
| 3 | 3 | ||
| 4 | def after_create(record) | 4 | def after_create(record) |
| 5 | - Event.create( | ||
| 6 | - project: record.project, | ||
| 7 | - target_id: record.id, | ||
| 8 | - target_type: record.class.name, | ||
| 9 | - action: Event.determine_action(record), | ||
| 10 | - author_id: record.author_id | ||
| 11 | - ) | 5 | + event_author_id = record.author_id |
| 6 | + | ||
| 7 | + # Skip status notes | ||
| 8 | + if record.kind_of?(Note) && record.note.include?("_Status changed to ") | ||
| 9 | + return true | ||
| 10 | + end | ||
| 11 | + | ||
| 12 | + if event_author_id | ||
| 13 | + Event.create( | ||
| 14 | + project: record.project, | ||
| 15 | + target_id: record.id, | ||
| 16 | + target_type: record.class.name, | ||
| 17 | + action: Event.determine_action(record), | ||
| 18 | + author_id: event_author_id | ||
| 19 | + ) | ||
| 20 | + end | ||
| 12 | end | 21 | end |
| 13 | 22 | ||
| 14 | def after_save(record) | 23 | def after_save(record) |
| 15 | - if record.changed.include?("closed") | 24 | + if record.changed.include?("closed") && record.author_id_of_changes |
| 16 | Event.create( | 25 | Event.create( |
| 17 | project: record.project, | 26 | project: record.project, |
| 18 | target_id: record.id, | 27 | target_id: record.id, |
app/observers/issue_observer.rb
| @@ -16,7 +16,7 @@ class IssueObserver < ActiveRecord::Observer | @@ -16,7 +16,7 @@ class IssueObserver < ActiveRecord::Observer | ||
| 16 | if status | 16 | if status |
| 17 | Note.create_status_change_note(issue, current_user, status) | 17 | Note.create_status_change_note(issue, current_user, status) |
| 18 | [issue.author, issue.assignee].compact.each do |recipient| | 18 | [issue.author, issue.assignee].compact.each do |recipient| |
| 19 | - Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user) | 19 | + Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user.id).deliver |
| 20 | end | 20 | end |
| 21 | end | 21 | end |
| 22 | end | 22 | end |
app/observers/note_observer.rb
| @@ -21,7 +21,7 @@ class NoteObserver < ActiveRecord::Observer | @@ -21,7 +21,7 @@ class NoteObserver < ActiveRecord::Observer | ||
| 21 | # Notifies the whole team except the author of note | 21 | # Notifies the whole team except the author of note |
| 22 | def notify_team(note) | 22 | def notify_team(note) |
| 23 | # Note: wall posts are not "attached" to anything, so fall back to "Wall" | 23 | # Note: wall posts are not "attached" to anything, so fall back to "Wall" |
| 24 | - noteable_type = note.noteable_type || "Wall" | 24 | + noteable_type = note.noteable_type.presence || "Wall" |
| 25 | notify_method = "note_#{noteable_type.underscore}_email".to_sym | 25 | notify_method = "note_#{noteable_type.underscore}_email".to_sym |
| 26 | 26 | ||
| 27 | if Notify.respond_to? notify_method | 27 | if Notify.respond_to? notify_method |
app/observers/project_observer.rb
| @@ -3,7 +3,8 @@ class ProjectObserver < ActiveRecord::Observer | @@ -3,7 +3,8 @@ class ProjectObserver < ActiveRecord::Observer | ||
| 3 | project.update_repository | 3 | project.update_repository |
| 4 | end | 4 | end |
| 5 | 5 | ||
| 6 | - def after_save(project) | 6 | + def after_update(project) |
| 7 | + project.send_move_instructions if project.namespace_id_changed? | ||
| 7 | end | 8 | end |
| 8 | 9 | ||
| 9 | def after_destroy(project) | 10 | def after_destroy(project) |
app/roles/account.rb
| @@ -47,7 +47,7 @@ module Account | @@ -47,7 +47,7 @@ module Account | ||
| 47 | end | 47 | end |
| 48 | 48 | ||
| 49 | def cared_merge_requests | 49 | def cared_merge_requests |
| 50 | - MergeRequest.where("author_id = :id or assignee_id = :id", id: self.id).opened | 50 | + MergeRequest.where("author_id = :id or assignee_id = :id", id: self.id) |
| 51 | end | 51 | end |
| 52 | 52 | ||
| 53 | def project_ids | 53 | def project_ids |
| @@ -105,4 +105,20 @@ module Account | @@ -105,4 +105,20 @@ module Account | ||
| 105 | def namespace_id | 105 | def namespace_id |
| 106 | namespace.try :id | 106 | namespace.try :id |
| 107 | end | 107 | end |
| 108 | + | ||
| 109 | + def authorized_groups | ||
| 110 | + @authorized_groups ||= begin | ||
| 111 | + groups = Group.where(id: self.projects.pluck(:namespace_id)).all | ||
| 112 | + groups = groups + self.groups | ||
| 113 | + groups.uniq | ||
| 114 | + end | ||
| 115 | + end | ||
| 116 | + | ||
| 117 | + def authorized_projects | ||
| 118 | + Project.authorized_for(self) | ||
| 119 | + end | ||
| 120 | + | ||
| 121 | + def my_own_projects | ||
| 122 | + Project.personal(self) | ||
| 123 | + end | ||
| 108 | end | 124 | end |
| @@ -0,0 +1,59 @@ | @@ -0,0 +1,59 @@ | ||
| 1 | +module NamespacedProject | ||
| 2 | + def transfer(new_namespace) | ||
| 3 | + Project.transaction do | ||
| 4 | + old_namespace = namespace | ||
| 5 | + self.namespace = new_namespace | ||
| 6 | + | ||
| 7 | + old_dir = old_namespace.try(:path) || '' | ||
| 8 | + new_dir = new_namespace.try(:path) || '' | ||
| 9 | + | ||
| 10 | + old_repo = if old_dir.present? | ||
| 11 | + File.join(old_dir, self.path) | ||
| 12 | + else | ||
| 13 | + self.path | ||
| 14 | + end | ||
| 15 | + | ||
| 16 | + if Project.where(path: self.path, namespace_id: new_namespace.try(:id)).present? | ||
| 17 | + raise TransferError.new("Project with same path in target namespace already exists") | ||
| 18 | + end | ||
| 19 | + | ||
| 20 | + Gitlab::ProjectMover.new(self, old_dir, new_dir).execute | ||
| 21 | + | ||
| 22 | + git_host.move_repository(old_repo, self) | ||
| 23 | + | ||
| 24 | + save! | ||
| 25 | + end | ||
| 26 | + rescue Gitlab::ProjectMover::ProjectMoveError => ex | ||
| 27 | + raise TransferError.new(ex.message) | ||
| 28 | + end | ||
| 29 | + | ||
| 30 | + def name_with_namespace | ||
| 31 | + @name_with_namespace ||= begin | ||
| 32 | + if namespace | ||
| 33 | + namespace.human_name + " / " + name | ||
| 34 | + else | ||
| 35 | + name | ||
| 36 | + end | ||
| 37 | + end | ||
| 38 | + end | ||
| 39 | + | ||
| 40 | + def namespace_owner | ||
| 41 | + namespace.try(:owner) | ||
| 42 | + end | ||
| 43 | + | ||
| 44 | + def chief | ||
| 45 | + if namespace | ||
| 46 | + namespace_owner | ||
| 47 | + else | ||
| 48 | + owner | ||
| 49 | + end | ||
| 50 | + end | ||
| 51 | + | ||
| 52 | + def path_with_namespace | ||
| 53 | + if namespace | ||
| 54 | + namespace.path + '/' + path | ||
| 55 | + else | ||
| 56 | + path | ||
| 57 | + end | ||
| 58 | + end | ||
| 59 | +end |
| @@ -0,0 +1,37 @@ | @@ -0,0 +1,37 @@ | ||
| 1 | +module NoteEvent | ||
| 2 | + def note_commit_id | ||
| 3 | + target.commit_id | ||
| 4 | + end | ||
| 5 | + | ||
| 6 | + def note_short_commit_id | ||
| 7 | + note_commit_id[0..8] | ||
| 8 | + end | ||
| 9 | + | ||
| 10 | + def note_commit? | ||
| 11 | + target.noteable_type == "Commit" | ||
| 12 | + end | ||
| 13 | + | ||
| 14 | + def note_target | ||
| 15 | + target.noteable | ||
| 16 | + end | ||
| 17 | + | ||
| 18 | + def note_target_id | ||
| 19 | + if note_commit? | ||
| 20 | + target.commit_id | ||
| 21 | + else | ||
| 22 | + target.noteable_id.to_s | ||
| 23 | + end | ||
| 24 | + end | ||
| 25 | + | ||
| 26 | + def wall_note? | ||
| 27 | + target.noteable_type.blank? | ||
| 28 | + end | ||
| 29 | + | ||
| 30 | + def note_target_type | ||
| 31 | + if target.noteable_type.present? | ||
| 32 | + target.noteable_type.titleize | ||
| 33 | + else | ||
| 34 | + "Wall" | ||
| 35 | + end.downcase | ||
| 36 | + end | ||
| 37 | +end |
app/roles/push_observer.rb
| @@ -114,7 +114,7 @@ module PushObserver | @@ -114,7 +114,7 @@ module PushObserver | ||
| 114 | id: commit.id, | 114 | id: commit.id, |
| 115 | message: commit.safe_message, | 115 | message: commit.safe_message, |
| 116 | timestamp: commit.date.xmlschema, | 116 | timestamp: commit.date.xmlschema, |
| 117 | - url: "#{Gitlab.config.url}/#{path}/commits/#{commit.id}", | 117 | + url: "#{Gitlab.config.gitlab.url}/#{path_with_namespace}/commit/#{commit.id}", |
| 118 | author: { | 118 | author: { |
| 119 | name: commit.author_name, | 119 | name: commit.author_name, |
| 120 | email: commit.author_email | 120 | email: commit.author_email |
app/roles/repository.rb
| @@ -45,8 +45,22 @@ module Repository | @@ -45,8 +45,22 @@ module Repository | ||
| 45 | end | 45 | end |
| 46 | 46 | ||
| 47 | def has_post_receive_file? | 47 | def has_post_receive_file? |
| 48 | - hook_file = File.join(path_to_repo, 'hooks', 'post-receive') | ||
| 49 | - File.exists?(hook_file) | 48 | + !!hook_file |
| 49 | + end | ||
| 50 | + | ||
| 51 | + def valid_post_receive_file? | ||
| 52 | + valid_hook_file == hook_file | ||
| 53 | + end | ||
| 54 | + | ||
| 55 | + def valid_hook_file | ||
| 56 | + @valid_hook_file ||= File.read(Rails.root.join('lib', 'hooks', 'post-receive')) | ||
| 57 | + end | ||
| 58 | + | ||
| 59 | + def hook_file | ||
| 60 | + @hook_file ||= begin | ||
| 61 | + hook_path = File.join(path_to_repo, 'hooks', 'post-receive') | ||
| 62 | + File.read(hook_path) if File.exists?(hook_path) | ||
| 63 | + end | ||
| 50 | end | 64 | end |
| 51 | 65 | ||
| 52 | # Returns an Array of branch names | 66 | # Returns an Array of branch names |
| @@ -83,7 +97,7 @@ module Repository | @@ -83,7 +97,7 @@ module Repository | ||
| 83 | end | 97 | end |
| 84 | 98 | ||
| 85 | def path_to_repo | 99 | def path_to_repo |
| 86 | - File.join(Gitlab.config.git_base_path, "#{path_with_namespace}.git") | 100 | + File.join(Gitlab.config.gitolite.repos_path, "#{path_with_namespace}.git") |
| 87 | end | 101 | end |
| 88 | 102 | ||
| 89 | def namespace_dir | 103 | def namespace_dir |
| @@ -185,7 +199,7 @@ module Repository | @@ -185,7 +199,7 @@ module Repository | ||
| 185 | end | 199 | end |
| 186 | 200 | ||
| 187 | def http_url_to_repo | 201 | def http_url_to_repo |
| 188 | - http_url = [Gitlab.config.url, "/", path_with_namespace, ".git"].join('') | 202 | + http_url = [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('') |
| 189 | end | 203 | end |
| 190 | 204 | ||
| 191 | # Check if current branch name is marked as protected in the system | 205 | # Check if current branch name is marked as protected in the system |
app/views/admin/groups/_form.html.haml
| @@ -1,12 +0,0 @@ | @@ -1,12 +0,0 @@ | ||
| 1 | -= form_for [:admin, @group] do |f| | ||
| 2 | - - if @group.errors.any? | ||
| 3 | - .alert-message.block-message.error | ||
| 4 | - %span= @group.errors.full_messages.first | ||
| 5 | - .clearfix.group_name_holder | ||
| 6 | - = f.label :name do | ||
| 7 | - Group name is | ||
| 8 | - .input | ||
| 9 | - = f.text_field :name, placeholder: "Example Group", class: "xxlarge" | ||
| 10 | - | ||
| 11 | - .form-actions | ||
| 12 | - = f.submit 'Save group', class: "btn save-btn" |
app/views/admin/groups/edit.html.haml
| 1 | -%h3.page_title Edit Group | ||
| 2 | -%br | ||
| 3 | -= render 'form' | 1 | +%h3.page_title Rename Group |
| 2 | +%hr | ||
| 3 | += form_for [:admin, @group] do |f| | ||
| 4 | + - if @group.errors.any? | ||
| 5 | + .alert-message.block-message.error | ||
| 6 | + %span= @group.errors.full_messages.first | ||
| 7 | + .clearfix.group_name_holder | ||
| 8 | + = f.label :name do | ||
| 9 | + Group name is | ||
| 10 | + .input | ||
| 11 | + = f.text_field :name, placeholder: "Example Group", class: "xxlarge" | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + .clearfix.group_name_holder | ||
| 16 | + = f.label :path do | ||
| 17 | + %span.cred Group path is | ||
| 18 | + .input | ||
| 19 | + = f.text_field :path, placeholder: "example-group", class: "xxlarge danger" | ||
| 20 | + %ul.cred | ||
| 21 | + %li Changing group path can have unintended side effects. | ||
| 22 | + %li Renaming group path will rename directory for all related projects | ||
| 23 | + %li It will change web url for access group and group projects. | ||
| 24 | + %li It will change the git path to repositories under this group. | ||
| 25 | + | ||
| 26 | + .form-actions | ||
| 27 | + = f.submit 'Rename group', class: "btn danger" | ||
| 28 | + = link_to 'Cancel', admin_groups_path, class: "btn cancel-btn" |
app/views/admin/groups/index.html.haml
| @@ -12,17 +12,24 @@ | @@ -12,17 +12,24 @@ | ||
| 12 | 12 | ||
| 13 | %table | 13 | %table |
| 14 | %thead | 14 | %thead |
| 15 | - %th Name | ||
| 16 | - %th Path | ||
| 17 | - %th Projects | ||
| 18 | - %th Edit | ||
| 19 | - %th.cred Danger Zone! | 15 | + %tr |
| 16 | + %th | ||
| 17 | + Name | ||
| 18 | + %i.icon-sort-down | ||
| 19 | + %th Path | ||
| 20 | + %th Projects | ||
| 21 | + %th Owner | ||
| 22 | + %th.cred Danger Zone! | ||
| 20 | 23 | ||
| 21 | - @groups.each do |group| | 24 | - @groups.each do |group| |
| 22 | %tr | 25 | %tr |
| 23 | - %td= link_to group.name, [:admin, group] | 26 | + %td |
| 27 | + %strong= link_to group.name, [:admin, group] | ||
| 24 | %td= group.path | 28 | %td= group.path |
| 25 | %td= group.projects.count | 29 | %td= group.projects.count |
| 26 | - %td= link_to 'Edit', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn small" | ||
| 27 | - %td.bgred= link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn small danger" | 30 | + %td |
| 31 | + = link_to group.owner_name, admin_user_path(group.owner_id) | ||
| 32 | + %td.bgred | ||
| 33 | + = link_to 'Rename', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn small" | ||
| 34 | + = link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn small danger" | ||
| 28 | = paginate @groups, theme: "admin" | 35 | = paginate @groups, theme: "admin" |
app/views/admin/groups/show.html.haml
| 1 | %h3.page_title | 1 | %h3.page_title |
| 2 | Group: #{@group.name} | 2 | Group: #{@group.name} |
| 3 | - = link_to edit_admin_group_path(@group), class: "btn right" do | ||
| 4 | - %i.icon-edit | ||
| 5 | - Edit | ||
| 6 | 3 | ||
| 7 | %br | 4 | %br |
| 8 | %table.zebra-striped | 5 | %table.zebra-striped |
| @@ -16,36 +13,64 @@ | @@ -16,36 +13,64 @@ | ||
| 16 | Name: | 13 | Name: |
| 17 | %td | 14 | %td |
| 18 | = @group.name | 15 | = @group.name |
| 16 | + | ||
| 17 | + = link_to edit_admin_group_path(@group), class: "btn btn-small right" do | ||
| 18 | + %i.icon-edit | ||
| 19 | + Rename | ||
| 19 | %tr | 20 | %tr |
| 20 | %td | 21 | %td |
| 21 | %b | 22 | %b |
| 22 | Path: | 23 | Path: |
| 23 | %td | 24 | %td |
| 24 | - %span.monospace= File.join(Gitlab.config.git_base_path, @group.path) | 25 | + %span.monospace= File.join(Gitlab.config.gitolite.repos_path, @group.path) |
| 25 | %tr | 26 | %tr |
| 26 | %td | 27 | %td |
| 27 | %b | 28 | %b |
| 28 | Owner: | 29 | Owner: |
| 29 | %td | 30 | %td |
| 30 | = @group.owner_name | 31 | = @group.owner_name |
| 31 | -.ui-box | ||
| 32 | - %h5 | ||
| 33 | - Projects | ||
| 34 | - %small | ||
| 35 | - (#{@group.projects.count}) | ||
| 36 | - %ul.unstyled | 32 | + .right |
| 33 | + = link_to "#", class: "btn btn-small change-owner-link" do | ||
| 34 | + %i.icon-edit | ||
| 35 | + Change owner | ||
| 36 | + | ||
| 37 | + %tr.change-owner-holder.hide | ||
| 38 | + %td.bgred | ||
| 39 | + %b.cred | ||
| 40 | + New Owner: | ||
| 41 | + %td.bgred | ||
| 42 | + = form_for [:admin, @group] do |f| | ||
| 43 | + = f.select :owner_id, User.all.map { |user| [user.name, user.id] }, {}, {class: 'chosen'} | ||
| 44 | + %div | ||
| 45 | + = f.submit 'Change Owner', class: "btn danger" | ||
| 46 | + = link_to "Cancel", "#", class: "btn change-owner-cancel-link" | ||
| 47 | +%fieldset | ||
| 48 | + %legend Projects (#{@group.projects.count}) | ||
| 49 | + %table | ||
| 50 | + %thead | ||
| 51 | + %tr | ||
| 52 | + %th Project name | ||
| 53 | + %th Path | ||
| 54 | + %th Users | ||
| 55 | + %th.cred Danger Zone! | ||
| 37 | - @group.projects.each do |project| | 56 | - @group.projects.each do |project| |
| 38 | - %li.wll | ||
| 39 | - %strong | ||
| 40 | - = link_to project.name, [:admin, project] | ||
| 41 | - .right | ||
| 42 | - = 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" | ||
| 43 | - .clearfix | 57 | + %tr |
| 58 | + %td | ||
| 59 | + = link_to project.name_with_namespace, [:admin, project] | ||
| 60 | + %td | ||
| 61 | + %span.monospace= project.path_with_namespace + ".git" | ||
| 62 | + %td= project.users.count | ||
| 63 | + %td.bgred | ||
| 64 | + = 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" | ||
| 44 | 65 | ||
| 45 | 66 | ||
| 46 | = form_tag project_update_admin_group_path(@group), class: "bulk_import", method: :put do | 67 | = form_tag project_update_admin_group_path(@group), class: "bulk_import", method: :put do |
| 47 | %fieldset | 68 | %fieldset |
| 48 | %legend Move projects to group | 69 | %legend Move projects to group |
| 70 | + .alert | ||
| 71 | + You can move only projects with existing repos | ||
| 72 | + %br | ||
| 73 | + Group projects will be moved in group directory and will not be accessible by old path | ||
| 49 | .clearfix | 74 | .clearfix |
| 50 | = label_tag :project_ids do | 75 | = label_tag :project_ids do |
| 51 | Projects | 76 | Projects |
| @@ -53,3 +78,17 @@ | @@ -53,3 +78,17 @@ | ||
| 53 | = select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' | 78 | = select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' |
| 54 | .form-actions | 79 | .form-actions |
| 55 | = submit_tag 'Add', class: "btn primary" | 80 | = submit_tag 'Add', class: "btn primary" |
| 81 | + | ||
| 82 | +:javascript | ||
| 83 | + $(function(){ | ||
| 84 | + var modal = $('.change-owner-holder'); | ||
| 85 | + $('.change-owner-link').bind("click", function(){ | ||
| 86 | + $(this).hide(); | ||
| 87 | + modal.show(); | ||
| 88 | + }); | ||
| 89 | + $('.change-owner-cancel-link').bind("click", function(){ | ||
| 90 | + modal.hide(); | ||
| 91 | + $('.change-owner-link').show(); | ||
| 92 | + }) | ||
| 93 | + }) | ||
| 94 | + |
app/views/admin/logs/show.html.haml
| @@ -3,6 +3,8 @@ | @@ -3,6 +3,8 @@ | ||
| 3 | = link_to "githost.log", "#githost", 'data-toggle' => 'tab' | 3 | = link_to "githost.log", "#githost", 'data-toggle' => 'tab' |
| 4 | %li | 4 | %li |
| 5 | = link_to "application.log", "#application", 'data-toggle' => 'tab' | 5 | = link_to "application.log", "#application", 'data-toggle' => 'tab' |
| 6 | + %li | ||
| 7 | + = link_to "production.log", "#production", 'data-toggle' => 'tab' | ||
| 6 | 8 | ||
| 7 | %p.light To prevent perfomance issues admin logs output the last 2000 lines | 9 | %p.light To prevent perfomance issues admin logs output the last 2000 lines |
| 8 | .tab-content | 10 | .tab-content |
| @@ -34,3 +36,17 @@ | @@ -34,3 +36,17 @@ | ||
| 34 | - Gitlab::AppLogger.read_latest.each do |line| | 36 | - Gitlab::AppLogger.read_latest.each do |line| |
| 35 | %li | 37 | %li |
| 36 | %p= line | 38 | %p= line |
| 39 | + .tab-pane#production | ||
| 40 | + .file_holder#README | ||
| 41 | + .file_title | ||
| 42 | + %i.icon-file | ||
| 43 | + production.log | ||
| 44 | + .right | ||
| 45 | + = link_to '#', class: 'log-bottom' do | ||
| 46 | + %i.icon-arrow-down | ||
| 47 | + Scroll down | ||
| 48 | + .file_content.logs | ||
| 49 | + %ol | ||
| 50 | + - Gitlab::Logger.read_latest_for('production.log').each do |line| | ||
| 51 | + %li | ||
| 52 | + %p= line |
app/views/admin/projects/_form.html.haml
| @@ -19,40 +19,47 @@ | @@ -19,40 +19,47 @@ | ||
| 19 | .input | 19 | .input |
| 20 | = text_field_tag :ppath, @project.path_to_repo, class: "xlarge", disabled: true | 20 | = text_field_tag :ppath, @project.path_to_repo, class: "xlarge", disabled: true |
| 21 | 21 | ||
| 22 | - - unless project.new_record? | 22 | + - if project.repo_exists? |
| 23 | .clearfix | 23 | .clearfix |
| 24 | - = f.label :namespace_id | ||
| 25 | - .input= f.select :namespace_id, namespaces_options(@project.namespace_id), {}, {class: 'chosen'} | 24 | + = f.label :default_branch, "Default Branch" |
| 25 | + .input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;") | ||
| 26 | 26 | ||
| 27 | - - if project.repo_exists? | ||
| 28 | - .clearfix | ||
| 29 | - = f.label :default_branch, "Default Branch" | ||
| 30 | - .input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;") | 27 | + %fieldset.adv_settings |
| 28 | + %legend Features: | ||
| 31 | 29 | ||
| 32 | - - unless project.new_record? | ||
| 33 | - %fieldset.adv_settings | ||
| 34 | - %legend Features: | 30 | + .clearfix |
| 31 | + = f.label :issues_enabled, "Issues" | ||
| 32 | + .input= f.check_box :issues_enabled | ||
| 35 | 33 | ||
| 36 | - .clearfix | ||
| 37 | - = f.label :issues_enabled, "Issues" | ||
| 38 | - .input= f.check_box :issues_enabled | 34 | + .clearfix |
| 35 | + = f.label :merge_requests_enabled, "Merge Requests" | ||
| 36 | + .input= f.check_box :merge_requests_enabled | ||
| 39 | 37 | ||
| 40 | - .clearfix | ||
| 41 | - = f.label :merge_requests_enabled, "Merge Requests" | ||
| 42 | - .input= f.check_box :merge_requests_enabled | 38 | + .clearfix |
| 39 | + = f.label :wall_enabled, "Wall" | ||
| 40 | + .input= f.check_box :wall_enabled | ||
| 43 | 41 | ||
| 44 | - .clearfix | ||
| 45 | - = f.label :wall_enabled, "Wall" | ||
| 46 | - .input= f.check_box :wall_enabled | 42 | + .clearfix |
| 43 | + = f.label :wiki_enabled, "Wiki" | ||
| 44 | + .input= f.check_box :wiki_enabled | ||
| 45 | + | ||
| 46 | + %fieldset.features | ||
| 47 | + %legend Transfer: | ||
| 48 | + .control-group | ||
| 49 | + = f.label :namespace_id do | ||
| 50 | + %span Namespace | ||
| 51 | + .controls | ||
| 52 | + = f.select :namespace_id, namespaces_options(@project.namespace_id, :all), {}, {class: 'chosen'} | ||
| 53 | + %br | ||
| 54 | + %ul.prepend-top-10.cred | ||
| 55 | + %li Be careful. Changing project namespace can have unintended side effects | ||
| 56 | + %li You can transfer project only to namespaces you can manage | ||
| 57 | + %li You will need to update your local repositories to point to the new location. | ||
| 47 | 58 | ||
| 48 | - .clearfix | ||
| 49 | - = f.label :wiki_enabled, "Wiki" | ||
| 50 | - .input= f.check_box :wiki_enabled | ||
| 51 | 59 | ||
| 52 | - - unless project.new_record? | ||
| 53 | - .actions | ||
| 54 | - = f.submit 'Save Project', class: "btn save-btn" | ||
| 55 | - = link_to 'Cancel', admin_projects_path, class: "btn cancel-btn" | 60 | + .actions |
| 61 | + = f.submit 'Save Project', class: "btn save-btn" | ||
| 62 | + = link_to 'Cancel', admin_projects_path, class: "btn cancel-btn" | ||
| 56 | 63 | ||
| 57 | 64 | ||
| 58 | 65 |
app/views/admin/projects/index.html.haml
| 1 | %h3.page_title | 1 | %h3.page_title |
| 2 | - Projects | 2 | + Projects (#{@projects.count}) |
| 3 | = link_to 'New Project', new_project_path, class: "btn small right" | 3 | = link_to 'New Project', new_project_path, class: "btn small right" |
| 4 | %br | 4 | %br |
| 5 | = form_tag admin_projects_path, method: :get, class: 'form-inline' do | 5 | = form_tag admin_projects_path, method: :get, class: 'form-inline' do |
| @@ -9,12 +9,15 @@ | @@ -9,12 +9,15 @@ | ||
| 9 | 9 | ||
| 10 | %table | 10 | %table |
| 11 | %thead | 11 | %thead |
| 12 | - %th Name | ||
| 13 | - %th Path | ||
| 14 | - %th Team Members | ||
| 15 | - %th Last Commit | ||
| 16 | - %th Edit | ||
| 17 | - %th.cred Danger Zone! | 12 | + %tr |
| 13 | + %th | ||
| 14 | + Name | ||
| 15 | + %i.icon-sort-down | ||
| 16 | + %th Path | ||
| 17 | + %th Team Members | ||
| 18 | + %th Last Commit | ||
| 19 | + %th Edit | ||
| 20 | + %th.cred Danger Zone! | ||
| 18 | 21 | ||
| 19 | - @projects.each do |project| | 22 | - @projects.each do |project| |
| 20 | %tr | 23 | %tr |
app/views/admin/projects/show.html.haml
| @@ -4,14 +4,24 @@ | @@ -4,14 +4,24 @@ | ||
| 4 | %i.icon-edit | 4 | %i.icon-edit |
| 5 | Edit | 5 | Edit |
| 6 | 6 | ||
| 7 | -- if !@project.has_post_receive_file? && @project.has_commits? | ||
| 8 | - %br | ||
| 9 | - .alert.alert-error | ||
| 10 | - %span | ||
| 11 | - %strong Important! | ||
| 12 | - Project has commits but missing post-receive file. | ||
| 13 | - %br | ||
| 14 | - If you exported project manually - copy post-receive hook to bare repository | 7 | +- if @project.has_commits? |
| 8 | + - if !@project.has_post_receive_file? | ||
| 9 | + %br | ||
| 10 | + .alert.alert-error | ||
| 11 | + %span | ||
| 12 | + %strong Project has commits but missing post-receive file. | ||
| 13 | + %br | ||
| 14 | + If you exported project manually - make a link of post-receive hook file from gitolite to project repository | ||
| 15 | + - elsif !@project.valid_post_receive_file? | ||
| 16 | + %br | ||
| 17 | + .alert.alert-error | ||
| 18 | + %span | ||
| 19 | + %strong Project has invalid post-receive file. | ||
| 20 | + %br | ||
| 21 | + 1. Make sure your gitolite instace has latest post-receive file. | ||
| 22 | + %br | ||
| 23 | + 2. Make a link of post-receive hook file from gitolite to project repository | ||
| 24 | + | ||
| 15 | 25 | ||
| 16 | %br | 26 | %br |
| 17 | %table.zebra-striped | 27 | %table.zebra-striped |
| @@ -37,9 +47,12 @@ | @@ -37,9 +47,12 @@ | ||
| 37 | %tr | 47 | %tr |
| 38 | %td | 48 | %td |
| 39 | %b | 49 | %b |
| 40 | - Path: | 50 | + Owned by: |
| 41 | %td | 51 | %td |
| 42 | - %code= @project.path_to_repo | 52 | + - if @project.chief |
| 53 | + = link_to @project.chief.name, admin_user_path(@project.chief) | ||
| 54 | + - else | ||
| 55 | + (deleted) | ||
| 43 | %tr | 56 | %tr |
| 44 | %td | 57 | %td |
| 45 | %b | 58 | %b |
| @@ -49,11 +62,48 @@ | @@ -49,11 +62,48 @@ | ||
| 49 | %tr | 62 | %tr |
| 50 | %td | 63 | %td |
| 51 | %b | 64 | %b |
| 65 | + Created at: | ||
| 66 | + %td | ||
| 67 | + = @project.created_at.stamp("March 1, 1999") | ||
| 68 | + | ||
| 69 | +%table.zebra-striped | ||
| 70 | + %thead | ||
| 71 | + %tr | ||
| 72 | + %th Repository | ||
| 73 | + %th | ||
| 74 | + %tr | ||
| 75 | + %td | ||
| 76 | + %b | ||
| 77 | + FS Path: | ||
| 78 | + %td | ||
| 79 | + %code= @project.path_to_repo | ||
| 80 | + %tr | ||
| 81 | + %td | ||
| 82 | + %b | ||
| 83 | + Smart HTTP: | ||
| 84 | + %td | ||
| 85 | + = link_to @project.http_url_to_repo | ||
| 86 | + %tr | ||
| 87 | + %td | ||
| 88 | + %b | ||
| 89 | + SSH: | ||
| 90 | + %td | ||
| 91 | + = link_to @project.ssh_url_to_repo | ||
| 92 | + %tr | ||
| 93 | + %td | ||
| 94 | + %b | ||
| 95 | + Last commit at: | ||
| 96 | + %td | ||
| 97 | + = last_commit(@project) | ||
| 98 | + %tr | ||
| 99 | + %td | ||
| 100 | + %b | ||
| 52 | Post Receive File: | 101 | Post Receive File: |
| 53 | %td | 102 | %td |
| 54 | = check_box_tag :post_receive_file, 1, @project.has_post_receive_file?, disabled: true | 103 | = check_box_tag :post_receive_file, 1, @project.has_post_receive_file?, disabled: true |
| 104 | + | ||
| 55 | %br | 105 | %br |
| 56 | -%h3 | 106 | +%h5 |
| 57 | Team | 107 | Team |
| 58 | %small | 108 | %small |
| 59 | (#{@project.users_projects.count}) | 109 | (#{@project.users_projects.count}) |
| @@ -75,7 +125,7 @@ | @@ -75,7 +125,7 @@ | ||
| 75 | %td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn danger small" | 125 | %td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn danger small" |
| 76 | 126 | ||
| 77 | %br | 127 | %br |
| 78 | -%h3 Add new team member | 128 | +%h5 Add new team member |
| 79 | %br | 129 | %br |
| 80 | = form_tag team_update_admin_project_path(@project), class: "bulk_import", method: :put do | 130 | = form_tag team_update_admin_project_path(@project), class: "bulk_import", method: :put do |
| 81 | %table.zebra-striped | 131 | %table.zebra-striped |
app/views/admin/users/index.html.haml
| 1 | %h3.page_title | 1 | %h3.page_title |
| 2 | - Users | 2 | + Users (#{@admin_users.count}) |
| 3 | = link_to 'New User', new_admin_user_path, class: "btn small right" | 3 | = link_to 'New User', new_admin_user_path, class: "btn small right" |
| 4 | %br | 4 | %br |
| 5 | 5 | ||
| @@ -21,13 +21,16 @@ | @@ -21,13 +21,16 @@ | ||
| 21 | 21 | ||
| 22 | %table | 22 | %table |
| 23 | %thead | 23 | %thead |
| 24 | - %th Admin | ||
| 25 | - %th Name | ||
| 26 | - %th Username | ||
| 27 | - %th Email | ||
| 28 | - %th Projects | ||
| 29 | - %th Edit | ||
| 30 | - %th.cred Danger Zone! | 24 | + %tr |
| 25 | + %th Admin | ||
| 26 | + %th | ||
| 27 | + Name | ||
| 28 | + %i.icon-sort-down | ||
| 29 | + %th Username | ||
| 30 | + %th Email | ||
| 31 | + %th Projects | ||
| 32 | + %th Edit | ||
| 33 | + %th.cred Danger Zone! | ||
| 31 | 34 | ||
| 32 | - @admin_users.each do |user| | 35 | - @admin_users.each do |user| |
| 33 | %tr | 36 | %tr |
| @@ -38,10 +41,13 @@ | @@ -38,10 +41,13 @@ | ||
| 38 | %td= user.users_projects.count | 41 | %td= user.users_projects.count |
| 39 | %td= link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn small" | 42 | %td= link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn small" |
| 40 | %td.bgred | 43 | %td.bgred |
| 41 | - - if user.blocked | ||
| 42 | - = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn small success" | 44 | + - if user == current_user |
| 45 | + %span.cred It's you! | ||
| 43 | - else | 46 | - else |
| 44 | - = link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small danger" | ||
| 45 | - = link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn small danger" | 47 | + - if user.blocked |
| 48 | + = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn small success" | ||
| 49 | + - else | ||
| 50 | + = link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small danger" | ||
| 51 | + = link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn small danger" | ||
| 46 | 52 | ||
| 47 | = paginate @admin_users, theme: "admin" | 53 | = paginate @admin_users, theme: "admin" |
app/views/admin/users/show.html.haml
| @@ -40,6 +40,12 @@ | @@ -40,6 +40,12 @@ | ||
| 40 | %tr | 40 | %tr |
| 41 | %td | 41 | %td |
| 42 | %b | 42 | %b |
| 43 | + Created at: | ||
| 44 | + %td | ||
| 45 | + = @admin_user.created_at.stamp("March 1, 1999") | ||
| 46 | + %tr | ||
| 47 | + %td | ||
| 48 | + %b | ||
| 43 | Projects limit: | 49 | Projects limit: |
| 44 | %td | 50 | %td |
| 45 | = @admin_user.projects_limit | 51 | = @admin_user.projects_limit |
| @@ -66,7 +72,7 @@ | @@ -66,7 +72,7 @@ | ||
| 66 | = @admin_user.twitter | 72 | = @admin_user.twitter |
| 67 | 73 | ||
| 68 | %br | 74 | %br |
| 69 | -%h3 Add User to Projects | 75 | +%h5 Add User to Projects |
| 70 | %br | 76 | %br |
| 71 | = form_tag team_update_admin_user_path(@admin_user), class: "bulk_import", method: :put do | 77 | = form_tag team_update_admin_user_path(@admin_user), class: "bulk_import", method: :put do |
| 72 | %table | 78 | %table |
| @@ -76,7 +82,7 @@ | @@ -76,7 +82,7 @@ | ||
| 76 | %th Project Access: | 82 | %th Project Access: |
| 77 | 83 | ||
| 78 | %tr | 84 | %tr |
| 79 | - %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' | 85 | + %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' |
| 80 | %td= select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select chosen span3" | 86 | %td= select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select chosen span3" |
| 81 | 87 | ||
| 82 | %tr | 88 | %tr |
| @@ -86,8 +92,22 @@ | @@ -86,8 +92,22 @@ | ||
| 86 | %strong= link_to "here", help_permissions_path, class: "vlink" | 92 | %strong= link_to "here", help_permissions_path, class: "vlink" |
| 87 | %br | 93 | %br |
| 88 | 94 | ||
| 95 | +- if @admin_user.groups.present? | ||
| 96 | + %h5 Owner of groups: | ||
| 97 | + %br | ||
| 98 | + | ||
| 99 | + %table.zebra-striped | ||
| 100 | + %thead | ||
| 101 | + %tr | ||
| 102 | + %th Name | ||
| 103 | + | ||
| 104 | + - @admin_user.groups.each do |group| | ||
| 105 | + %tr | ||
| 106 | + %td= link_to group.name, admin_group_path(group) | ||
| 107 | + | ||
| 108 | + | ||
| 89 | - if @admin_user.projects.present? | 109 | - if @admin_user.projects.present? |
| 90 | - %h3 Projects | 110 | + %h5 Projects: |
| 91 | %br | 111 | %br |
| 92 | 112 | ||
| 93 | %table.zebra-striped | 113 | %table.zebra-striped |
| @@ -101,7 +121,7 @@ | @@ -101,7 +121,7 @@ | ||
| 101 | - @admin_user.users_projects.each do |tm| | 121 | - @admin_user.users_projects.each do |tm| |
| 102 | - project = tm.project | 122 | - project = tm.project |
| 103 | %tr | 123 | %tr |
| 104 | - %td= link_to project.name, admin_project_path(project) | 124 | + %td= link_to project.name_with_namespace, admin_project_path(project) |
| 105 | %td= tm.project_access_human | 125 | %td= tm.project_access_human |
| 106 | %td= link_to 'Edit Access', edit_admin_team_member_path(tm), class: "btn small" | 126 | %td= link_to 'Edit Access', edit_admin_team_member_path(tm), class: "btn small" |
| 107 | %td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn small danger" | 127 | %td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn small danger" |