diff options
443 files changed, 7191 insertions, 5750 deletions
diff --git a/.gitignore b/.gitignore index 725f289db55..760487ca9b3 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ config/database.yml config/initializers/omniauth.rb config/unicorn.rb db/data.yml +.idea +.DS_Store + diff --git a/.rails_footnotes b/.rails_footnotes deleted file mode 100644 index 1019a70aa1b..00000000000 --- a/.rails_footnotes +++ /dev/null @@ -1,3 +0,0 @@ -#this code temporarily disables notes for all controllers -# Footnotes::Filter.notes = [] - diff --git a/.travis.yml b/.travis.yml index 402fc8e0dd2..da67e37dbd0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,9 @@ env: - DB=mysql - - DB=sqlite before_install: - sudo apt-get install libicu-dev -y + - sudo apt-get install libqt4-dev libqtwebkit-dev -y - gem install charlock_holmes -v="0.6.8" - - echo "yes" | gem uninstall json ffi branches: only: - 'master' diff --git a/CHANGELOG b/CHANGELOG index fe243d65e4b..6868c07ba52 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,9 +1,29 @@ +v 2.8.1 + - ability to disable gravatars + - improved MR diff logic + - ssh key help page + +v 2.8.0 + - Gitlab Flavored Markdown + - Bulk issues update + - Issues API + - Cucumber coverage increased + - Post-receive files fixed + - UI improved + - Application cleanup + - more cucumber + - capybara-webkit + headless + v 2.7.0 - Issue Labels - Inline diff - Git HTTP - API - UI improved + - System hooks + - UI improved + - Dashboard events endless scroll + - Source perfomance increased v 2.6.0 - UI polished @@ -1,6 +1,6 @@ source "http://rubygems.org" -gem "rails", "3.2.5" +gem "rails", "3.2.8" # Supported DBs gem "sqlite3" @@ -13,35 +13,69 @@ gem "devise", "~> 2.1.0" gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837" gem "gitolite", :git => "https://github.com/gitlabhq/gitolite-client.git", :ref => "9b715ca8bab6529f6c92204a25f84d12f25a6eb0" gem "pygments.rb", :git => "https://github.com/gitlabhq/pygments.rb.git", :ref => "2cada028da5054616634a1d9ca6941b65b3ce188" -gem "omniauth-ldap", :git => "https://github.com/gitlabhq/omniauth-ldap.git", :ref => "7edf27d0281e09561838122982c16b7e62181f44" +gem "omniauth-ldap", :git => "https://github.com/gitlabhq/omniauth-ldap.git", :ref => "f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e" gem 'yaml_db', :git => "https://github.com/gitlabhq/yaml_db.git" gem 'grack', :git => "https://github.com/gitlabhq/grack.git" gem "linguist", "~> 1.0.0", :git => "https://github.com/gitlabhq/linguist.git" -gem "grape" +# API +gem "grape", "~> 0.2.1" + +# Format dates and times +# based on human-friendly examples gem "stamp" + +# Pagination gem "kaminari" + +# HAML gem "haml-rails" + +# Files attachments gem "carrierwave" + +# Authorization gem "six" + +# Generate Fake data gem "ffaker" + +# Seed data gem "seed-fu" + +# Markdown to HTML gem "redcarpet", "~> 2.1.1" + +# Servers gem "thin" gem "unicorn" -gem "git" -gem "acts_as_list" + +# Issue tags gem "acts-as-taggable-on", "2.3.1" -gem "drapper" + +# Decorators +gem "draper" + +# Background jobs gem "resque", "~> 1.20.0" +gem 'resque_mailer' + +# HTTP requests gem "httparty" + +# Handle encodings gem "charlock_holmes" -gem "foreman" + +# Colored output to console gem "colored" -gem 'resque_mailer' -gem 'tabs_on_rails' + +# GITLAB settings gem 'settingslogic' +# Misc +gem "foreman" +gem "git" + group :assets do gem "sass-rails", "3.2.5" gem "coffee-rails", "3.2.2" @@ -53,33 +87,37 @@ group :assets do gem "jquery-ui-rails", "0.5.0" gem "modernizr", "2.5.3" gem "raphael-rails", "1.5.2" - gem 'bootstrap-sass', "2.0.3.1" + gem 'bootstrap-sass', "2.0.4" end group :development do gem "letter_opener" - gem "rails-footnotes" gem "annotate", :git => "https://github.com/ctran/annotate_models.git" + gem 'rack-mini-profiler' end group :development, :test do gem "rspec-rails" gem "capybara" + gem "capybara-webkit" + gem "headless" gem "autotest" gem "autotest-rails" gem "pry" gem "awesome_print" gem "database_cleaner" gem "launchy" - gem "webmock" end group :test do gem 'cucumber-rails', :require => false - gem 'minitest', ">= 2.10" - gem "turn", :require => false gem "simplecov", :require => false gem "shoulda-matchers" gem 'email_spec' gem 'resque_spec' + gem "webmock" +end + +group :production do + gem "gitlab_meta", '2.8' end diff --git a/Gemfile.lock b/Gemfile.lock index e4c06fed229..656bede4766 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -42,8 +42,8 @@ GIT GIT remote: https://github.com/gitlabhq/omniauth-ldap.git - revision: 7edf27d0281e09561838122982c16b7e62181f44 - ref: 7edf27d0281e09561838122982c16b7e62181f44 + revision: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e + ref: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e specs: omniauth-ldap (1.0.2) net-ldap (~> 0.2.2) @@ -69,38 +69,36 @@ GEM remote: http://rubygems.org/ specs: ZenTest (4.8.1) - actionmailer (3.2.5) - actionpack (= 3.2.5) + actionmailer (3.2.8) + actionpack (= 3.2.8) mail (~> 2.4.4) - actionpack (3.2.5) - activemodel (= 3.2.5) - activesupport (= 3.2.5) + actionpack (3.2.8) + activemodel (= 3.2.8) + activesupport (= 3.2.8) builder (~> 3.0.0) erubis (~> 2.7.0) - journey (~> 1.0.1) + journey (~> 1.0.4) rack (~> 1.4.0) rack-cache (~> 1.2) rack-test (~> 0.6.1) sprockets (~> 2.1.3) - activemodel (3.2.5) - activesupport (= 3.2.5) + activemodel (3.2.8) + activesupport (= 3.2.8) builder (~> 3.0.0) - activerecord (3.2.5) - activemodel (= 3.2.5) - activesupport (= 3.2.5) + activerecord (3.2.8) + activemodel (= 3.2.8) + activesupport (= 3.2.8) arel (~> 3.0.2) tzinfo (~> 0.3.29) - activeresource (3.2.5) - activemodel (= 3.2.5) - activesupport (= 3.2.5) - activesupport (3.2.5) + activeresource (3.2.8) + activemodel (= 3.2.8) + activesupport (= 3.2.8) + activesupport (3.2.8) i18n (~> 0.6) multi_json (~> 1.0) acts-as-taggable-on (2.3.1) rails (~> 3.0) - acts_as_list (0.1.6) addressable (2.2.8) - ansi (1.4.2) arel (3.0.2) autotest (4.4.6) ZenTest (>= 4.4.1) @@ -109,7 +107,7 @@ GEM awesome_print (1.0.2) bcrypt-ruby (3.0.1) blankslate (2.1.2.4) - bootstrap-sass (2.0.3.1) + bootstrap-sass (2.0.4.0) builder (3.0.0) capybara (1.1.2) mime-types (>= 1.16) @@ -118,6 +116,9 @@ GEM rack-test (>= 0.5.4) selenium-webdriver (~> 2.0) xpath (~> 0.1.4) + capybara-webkit (0.12.1) + capybara (>= 1.0.0, < 1.2) + json carrierwave (0.6.2) activemodel (>= 3.2.0) activesupport (>= 3.2.0) @@ -154,7 +155,9 @@ GEM railties (~> 3.1) warden (~> 1.2.1) diff-lcs (1.1.3) - drapper (0.8.4) + draper (0.17.0) + actionpack (~> 3.2) + activesupport (~> 3.2) email_spec (1.2.1) mail (~> 2.2) rspec (~> 2.0) @@ -170,7 +173,8 @@ GEM gherkin (2.11.0) json (>= 1.4.6) git (1.2.5) - grape (0.2.0) + gitlab_meta (2.8) + grape (0.2.1) hashie (~> 1.2) multi_json multi_xml @@ -184,19 +188,20 @@ GEM railties (~> 3.0) hashery (1.4.0) hashie (1.2.0) + headless (0.3.1) hike (1.2.1) httparty (0.8.3) multi_json (~> 1.0) multi_xml i18n (0.6.0) - journey (1.0.3) + journey (1.0.4) jquery-rails (2.0.2) railties (>= 3.2.0, < 5.0) thor (~> 0.14) jquery-ui-rails (0.5.0) jquery-rails railties (>= 3.1.0) - json (1.7.3) + json (1.7.4) kaminari (0.13.0) actionpack (>= 3.0.0) activesupport (>= 3.0.0) @@ -214,8 +219,7 @@ GEM mime-types (~> 1.16) treetop (~> 1.4.8) method_source (0.7.1) - mime-types (1.18) - minitest (3.1.0) + mime-types (1.19) modernizr (2.5.3) sprockets (~> 2.0) multi_json (1.3.6) @@ -237,6 +241,8 @@ GEM rack (1.4.1) rack-cache (1.2) rack (>= 0.4) + rack-mini-profiler (0.1.9) + rack (>= 1.1.3) rack-mount (0.8.3) rack (>= 1.0.0) rack-protection (1.2.0) @@ -245,19 +251,17 @@ GEM rack rack-test (0.6.1) rack (>= 1.0) - rails (3.2.5) - actionmailer (= 3.2.5) - actionpack (= 3.2.5) - activerecord (= 3.2.5) - activeresource (= 3.2.5) - activesupport (= 3.2.5) + rails (3.2.8) + actionmailer (= 3.2.8) + actionpack (= 3.2.8) + activerecord (= 3.2.8) + activeresource (= 3.2.8) + activesupport (= 3.2.8) bundler (~> 1.0) - railties (= 3.2.5) - rails-footnotes (3.7.8) - rails (>= 3.0.0) - railties (3.2.5) - actionpack (= 3.2.5) - activesupport (= 3.2.5) + railties (= 3.2.8) + railties (3.2.8) + actionpack (= 3.2.8) + activesupport (= 3.2.8) rack-ssl (~> 1.3.2) rake (>= 0.8.7) rdoc (~> 3.4) @@ -333,20 +337,17 @@ GEM tilt (~> 1.1, != 1.3.0) sqlite3 (1.3.6) stamp (0.1.6) - tabs_on_rails (2.1.1) therubyracer (0.10.1) libv8 (~> 3.3.10) thin (1.3.1) daemons (>= 1.0.9) eventmachine (>= 0.12.6) rack (>= 1.0.0) - thor (0.15.2) + thor (0.15.4) tilt (1.3.3) treetop (1.4.10) polyglot polyglot (>= 0.3.1) - turn (0.9.5) - ansi tzinfo (0.3.33) uglifier (1.0.3) execjs (>= 0.3.0) @@ -370,13 +371,13 @@ PLATFORMS DEPENDENCIES acts-as-taggable-on (= 2.3.1) - acts_as_list annotate! autotest autotest-rails awesome_print - bootstrap-sass (= 2.0.3.1) + bootstrap-sass (= 2.0.4) capybara + capybara-webkit carrierwave charlock_holmes chosen-rails @@ -385,16 +386,18 @@ DEPENDENCIES cucumber-rails database_cleaner devise (~> 2.1.0) - drapper + draper email_spec ffaker foreman git + gitlab_meta (= 2.8) gitolite! grack! - grape + grape (~> 0.2.1) grit! haml-rails + headless httparty jquery-rails (= 2.0.2) jquery-ui-rails (= 0.5.0) @@ -402,14 +405,13 @@ DEPENDENCIES launchy letter_opener linguist (~> 1.0.0)! - minitest (>= 2.10) modernizr (= 2.5.3) mysql2 omniauth-ldap! pry pygments.rb! - rails (= 3.2.5) - rails-footnotes + rack-mini-profiler + rails (= 3.2.8) raphael-rails (= 1.5.2) redcarpet (~> 2.1.1) resque (~> 1.20.0) @@ -424,10 +426,8 @@ DEPENDENCIES six sqlite3 stamp - tabs_on_rails therubyracer thin - turn uglifier (= 1.0.3) unicorn webmock @@ -1 +1 @@ -2.7.0pre +2.8.2 diff --git a/app/assets/fonts/korolev-medium-compressed.otf b/app/assets/fonts/korolev-medium-compressed.otf Binary files differnew file mode 100644 index 00000000000..e3817cec857 --- /dev/null +++ b/app/assets/fonts/korolev-medium-compressed.otf diff --git a/app/assets/images/file_dir.png b/app/assets/images/file_dir.png Binary files differindex bd941249c87..97b0539393d 100644 --- a/app/assets/images/file_dir.png +++ b/app/assets/images/file_dir.png diff --git a/app/assets/images/gitlab_classic.png b/app/assets/images/gitlab_classic.png Binary files differnew file mode 100644 index 00000000000..4e189e220ab --- /dev/null +++ b/app/assets/images/gitlab_classic.png diff --git a/app/assets/images/gitlab_default.png b/app/assets/images/gitlab_default.png Binary files differnew file mode 100644 index 00000000000..6e9dfb58896 --- /dev/null +++ b/app/assets/images/gitlab_default.png diff --git a/app/assets/images/gitlab_modern.png b/app/assets/images/gitlab_modern.png Binary files differnew file mode 100644 index 00000000000..b2d73b7a789 --- /dev/null +++ b/app/assets/images/gitlab_modern.png diff --git a/app/assets/images/logo_dark.png b/app/assets/images/logo_dark.png Binary files differnew file mode 100644 index 00000000000..fab64c2d5a9 --- /dev/null +++ b/app/assets/images/logo_dark.png diff --git a/app/assets/images/logo_white.png b/app/assets/images/logo_white.png Binary files differnew file mode 100644 index 00000000000..3f74025449c --- /dev/null +++ b/app/assets/images/logo_white.png diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 527b5c795e1..24d99a62ca5 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -7,8 +7,6 @@ //= require jquery //= require jquery.ui.all //= require jquery_ujs -//= require jquery.ui.selectmenu -//= require jquery.tagify //= require jquery.cookie //= require jquery.endless-scroll //= require jquery.highlight @@ -26,7 +24,6 @@ $(document).ready(function(){ $(this).select(); }); - $('body').on('ajax:complete, ajax:beforeSend, submit', 'form', function(e){ var buttons = $('[type="submit"]', this); switch( e.type ){ @@ -52,14 +49,6 @@ $(document).ready(function(){ } }); - $("#issues-table .issue").live('click', function(e){ - if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") { - location.href = $(this).attr("url"); - e.stopPropagation(); - return false; - } - }); - /** * Focus search field by pressing 's' key */ @@ -78,6 +67,26 @@ $(document).ready(function(){ $(".supp_diff_link").bind("click", function() { showDiff(this); }); + + /** + * Note markdown preview + * + */ + $(document).on('click', '#preview-link', function(e) { + $('#preview-note').text('Loading...'); + + var previewLinkText = ($(this).text() == 'Preview' ? 'Edit' : 'Preview'); + $(this).text(previewLinkText); + + var note = $('#note_note').val(); + if (note.trim().length === 0) { note = 'Nothing to preview'; } + $.post($(this).attr('href'), {note: note}, function(data) { + $('#preview-note').html(data); + }); + + $('#preview-note, #note_note').toggle(); + e.preventDefault(); + }); }); function focusSearch() { @@ -116,6 +125,6 @@ function showDiff(link) { })(jQuery); -function ajaxGet(url) { - $.ajax({type: "GET", url: url, dataType: "script"}); +function ajaxGet(url) { + $.ajax({type: "GET", url: url, dataType: "script"}); } diff --git a/app/assets/javascripts/issues.js b/app/assets/javascripts/issues.js index 0acf9ec8aef..bc0569654e1 100644 --- a/app/assets/javascripts/issues.js +++ b/app/assets/javascripts/issues.js @@ -67,6 +67,10 @@ function initIssuesSearch() { */ function issuesPage(){ initIssuesSearch(); + $("#update_status").chosen(); + $("#update_assignee_id").chosen(); + $("#update_milestone_id").chosen(); + $("#label_name").chosen(); $("#assignee_id").chosen(); $("#milestone_id").chosen(); @@ -94,4 +98,29 @@ function issuesPage(){ }); }); + + $(".check_all_issues").click(function () { + $('.selected_issue').attr('checked', this.checked); + issuesCheckChanged(); + }); + + $('.selected_issue').bind('change', issuesCheckChanged); +} + +function issuesCheckChanged() { + var checked_issues = $('.selected_issue:checked'); + + if(checked_issues.length > 0) { + var ids = [] + $.each(checked_issues, function(index, value) { + ids.push($(value).attr("data-id")); + }) + $('#update_issues_ids').val(ids); + $('.issues_filters').hide(); + $('.issues_bulk_update').show(); + } else { + $('#update_issues_ids').val([]); + $('.issues_bulk_update').hide(); + $('.issues_filters').show(); + } } diff --git a/app/assets/javascripts/merge_requests.js b/app/assets/javascripts/merge_requests.js index 4b1551927c5..0ab6f6e22a1 100644 --- a/app/assets/javascripts/merge_requests.js +++ b/app/assets/javascripts/merge_requests.js @@ -112,6 +112,7 @@ var MergeRequest = { already_cannot_be_merged: function(){ $(".automerge_widget").hide(); + $(".merge_in_progress").hide(); $(".automerge_widget.already_cannot_be_merged").show(); } } diff --git a/app/assets/javascripts/note.js b/app/assets/javascripts/note.js index c45a45d2fcb..d9ae45d93c7 100644 --- a/app/assets/javascripts/note.js +++ b/app/assets/javascripts/note.js @@ -33,7 +33,7 @@ init: }) $("#note_note").live("focus", function(){ - $(this).css("height", "100px"); + $(this).css("height", "80px"); $('.note_advanced_opts').show(); }); diff --git a/app/assets/javascripts/pager.js b/app/assets/javascripts/pager.js index d42ae1e05d1..769e8a62343 100644 --- a/app/assets/javascripts/pager.js +++ b/app/assets/javascripts/pager.js @@ -8,7 +8,6 @@ var Pager = { this.limit=limit; this.offset=limit; this.initLoadMore(); - $('.loading').show(); }, getOld: diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 6ce23320984..92d542a9866 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -3,8 +3,7 @@ * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at * the top of the compiled file, but it's generally better to create a new file per style scope. *= require jquery.ui.all - *= require jquery-ui/jquery.ui.selectmenu - *= require jquery-ui/jquery.tagify + *= require jquery.ui.aristo *= require chosen *= require_self *= require main diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index 0db803aae23..68f862b8d2a 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -6,28 +6,28 @@ /** LAYOUT **/ -.container { +.container { padding-top:0; z-index:5; } -.container .content { +.container .content { margin:0 0; } -.container .sidebar { +.container .sidebar { width: 200px; height:100%; min-height:450px; float:right; } -.profile_avatar_holder { +.profile_avatar_holder { float:left; width:60px; height:60px; margin-right:20px; - img { + img { width:60px; height:60px; background:#eee; @@ -36,11 +36,11 @@ .visible_link, -.author_link { +.author_link { color: $link_color; } -.widget { +.widget { @include shade; padding:20px; margin-bottom:20px; @@ -48,7 +48,7 @@ border-radius: 5px; background:#fafafa; - .link_holder { + .link_holder { background:#eee; position:relative; left:-20px; @@ -57,16 +57,16 @@ width:100%; border-top:1px solid #ccc; - a { + a { font-size:14px; color:#666; } } } -.help li { color:#111 } +.help li { color:#111 } -.back_link { +.back_link { text-decoration:underline; font-size:14px; font-weight:bold; @@ -74,31 +74,31 @@ padding-bottom:0; } -.info_link { +.info_link { margin-right:5px; float:left; - img { + img { width:20px; } } -.download_repo_link { +.download_repo_link { background: url("images.png") no-repeat 0 -48px; padding-left:20px; } -.number { - border-radius: 4px; - text-shadow: none; - background: rgba(0,0,0,.12); - text-align: center; - padding: 2px 4px; +.number { + border-radius: 4px; + text-shadow: none; + background: rgba(0,0,0,.12); + text-align: center; + padding: 2px 4px; line-height:18px; margin-left:2px; } -table a code { +table a code { position: relative; top: -2px; margin-right: 3px; @@ -108,7 +108,7 @@ table a code { margin-top: 5px; } -.loading { +.loading { margin:20px auto; background: url(ajax_loader.gif) no-repeat center center; width:40px; @@ -129,10 +129,12 @@ table a code { border-bottom:1px solid #ccc; h4 { - color:#444; - font-size:22px; + color:#666; + font-size:18px; + line-height:38px; padding-top:5px; margin:2px; + font-weight:normal; } } @@ -198,12 +200,12 @@ a.project-update.titled { } } -input.git_clone_url { +input.git_clone_url { width:325px; } .merge-request-form-holder { - select { + select { width:300px; } } @@ -217,17 +219,17 @@ input.git_clone_url { height: 100px; } -.project_list_url { +.project_list_url { width:250px; background:#fff !important; } /** bordered list **/ -ul.bordered-list { +ul.bordered-list { margin:5px 0px; padding:0px; - li { + li { padding: 5px 0; border-bottom: 1px solid #EEE; overflow: hidden; @@ -236,25 +238,25 @@ ul.bordered-list { } } -ul.bordered-list li:last-child { border:none } +ul.bordered-list li:last-child { border:none } -.line_holder { - &:hover { - td { +.line_holder { + &:hover { + td { background: #FFFFCF !important; } } } -li.commit { - .avatar { +li.commit { + .avatar { width:24px; - top:-3px; + top:-5px; margin-right:10px; margin-left:10px; } - code { + code { padding: 2px 2px 0; margin-top: -2px; &:hover { @@ -270,21 +272,21 @@ p.time { } -/** +/** * Dashboard page - * + * */ -.dashboard_category { +.dashboard_category { margin-bottom:30px; - h3 a { + h3 a { color:#474D57; - &:hover { + &:hover { text-decoration:underline; } } - .dashboard_block { - .dash_project_item { + .dashboard_block { + .dash_project_item { margin-bottom:10px; border:none; padding:0px 5px; @@ -292,7 +294,7 @@ p.time { color:#888; &:hover { color:#111; - .ico.project { + .ico.project { background-position:-209px -21px; } } @@ -304,32 +306,27 @@ p.time { } } -.styled_image { - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - -moz-box-shadow: 0 0 5px #888; - -webkit-box-shadow: 0 0 5px#888; - box-shadow: 0 0 5px #888; +.styled_image { + border:2px solid #ddd; } -.event_feed { +.event_feed { min-height:40px; border-bottom:1px solid #ddd; - .avatar { + .avatar { width:32px; } - .event_icon { + .event_icon { float:right; margin-right:2px; - img { + img { width:20px; } } - ul { + ul { margin-left:50px; margin-bottom:5px; - .avatar { + .avatar { width:24px; } } @@ -337,9 +334,19 @@ p.time { padding: 15px 5px; &:last-child { border:none } .wll:hover { background:none } + + .event_commits { + margin-top: 5px; + + li.commit { + background: transparent; + padding:5px; + border:none; + } + } } -.ico { +.ico { background: url("images.png") no-repeat -85px -77px; width: 19px; height: 16px; @@ -348,24 +355,24 @@ p.time { margin-right: 10px; top: 8px; - &.project { + &.project { background-position: -37px -77px; } - &.activities { + &.activities { background-position:-162px -22px; } - &.projects { + &.projects { background-position:-209px -21px; } } -.leftbar { - h5, .title { +.leftbar { + h5, .title { padding:5px 10px; } - h4 { + h4 { font-size:14px; padding:2px 10px; color:#666; @@ -373,41 +380,41 @@ p.time { } a:last-child h4 { border:none; } - a:hover { + a:hover { h4 { color:#111; background:$hover; border-color:#CCC; - .ico.project { + .ico.project { background-position:-209px -21px; } } } - .bottom { + .bottom { padding:10px; } } -.btn { - &.very_small { +.btn { + &.very_small { font-size:11px; padding:2px 6px; margin:2px; } - &.grouped { + &.grouped { margin-right:7px; float:left; } - &.padded { + &.padded { margin-right:3px; padding:4px 10px 4px; } } -.prettyprint { +.prettyprint { background-color: #fefbf3; padding: 9px; border: 1px solid rgba(0,0,0,.2); @@ -434,7 +441,7 @@ p.time { .readme { pre { background: white !important; - + code { background: none !important; } @@ -442,11 +449,11 @@ p.time { } -.highlight_word { +.highlight_word { background:#EEDC94; } -.status_info { +.status_info { font-size:14px; padding:5px 15px; line-height:24px; @@ -455,13 +462,13 @@ p.time { float:left; margin-right:20px; - &.success { + &.success { background: #5BB75B; color: white; text-shadow: 0 1px #111; border-color: #9A9; } - &.error { + &.error { background: #DA4E49; border-color: #BD362F; color: white; @@ -469,7 +476,7 @@ p.time { } } -.arrow{ +.arrow{ background: #E3E5EA; padding: 5px; margin-top:5px; @@ -484,12 +491,12 @@ p.time { height: 150px; } -.gitlab_pagination { +.gitlab_pagination { span a { color:$link_color; } - .prev, .next, .current, .page a { + .prev, .next, .current, .page a { padding:10px; } - .current { + .current { border-bottom:2px solid $style_color; } } @@ -515,8 +522,8 @@ li.note { } } -.markdown { - img { +.markdown { + img { max-width:100%; } } @@ -525,20 +532,20 @@ li.note { background-color: inherit; } -.team_member_show { - td:first-child { +.team_member_show { + td:first-child { color:#aaa; } } -.remember_me { +.remember_me { text-align:left; - input { + input { margin:0; } - span { + span { padding-left:5px; } } @@ -549,7 +556,7 @@ li.note { * */ -.milestone { +.milestone { @extend .wll; } @@ -557,10 +564,10 @@ li.note { * Admin area * */ -.admin_dash { - .data { - a { - h1 { +.admin_dash { + .data { + a { + h1 { line-height:48px; font-size:48px; padding:20px; @@ -576,7 +583,7 @@ li.note { vertical-align:top; } - strong { + strong { line-height:24px; } } @@ -584,20 +591,20 @@ li.note { /* CHZN reset few styles */ -.chzn-container-single .chzn-single { +.chzn-container-single .chzn-single { background:#FFF; border: 1px solid #bbb; box-shadow:none; } -.chzn-container-active .chzn-single { +.chzn-container-active .chzn-single { background:#fff; } /** * Push event widget - * + * */ -.event_lp { +.event_lp { @extend .alert-info; margin-bottom:20px; padding:8px; @@ -606,19 +613,19 @@ li.note { @include border-radius(4px); min-height:22px; - .avatar { + .avatar { width:24px; } } .supp_diff_link, -.mr_show_all_commits { +.mr_show_all_commits { cursor:pointer; } /** - * Issues, MRs legend - * + * Issues, MRs legend + * */ .list_legend { @@ -631,32 +638,32 @@ li.note { margin-right:5px; margin-top: 2px; @include border-radius(4px); - &.today{ + &.today{ background: #ADA; border:1px solid #8B8; } - &.closed { + &.closed { background: #DDD; border:1px solid #BBB; } - &.yours { + &.yours { background: #AAD; border:1px solid #88B; } - &.merged { + &.merged { background: #DAD; border:1px solid #B8B; } } - .text { + .text { padding-bottom: 10px; float:left; } } .merge_request, -.issue { - .list_legend { +.issue { + .list_legend { margin-right: 5px; margin-top: 14px; .icon { @@ -669,34 +676,72 @@ li.note { } } - &.today{ + &.today{ background: #EFE; border-color:#CEC; - .icon { + .icon { background: #ADA; border:1px solid #8B8; } } - &.closed { + &.closed { background: #F5f5f5; border-color:#E5E5E5; - .icon { + .icon { background: #DDD; border:1px solid #BBB; } } - &.yours { - .icon { + &.yours { + .icon { background: #AAD; border:1px solid #88B; } } - &.merged { + &.merged { background: #F5f5f5; border-color:#E5E5E5; - .icon { + .icon { background: #DAD; border:1px solid #B8B; } } } + +.themes_opts { + padding-left:20px; + + label { + width:175px; + margin-right:40px; + + .prev { + @extend .borders; + height:120px; + width:175px; + margin-bottom:10px; + img { + width:180px; + } + } + } +} + +.git_error_tips { + @extend .span6; + text-align:left; + margin-top:40px; + pre { + background:white; + border:none; + font-size: 12px; + } +} + +.error_message { + @extend .cred; + border-bottom: 1px solid #D21; + padding-bottom:20px; + text-align:center; + margin-bottom:10px; +} diff --git a/app/assets/stylesheets/gitlab_bootstrap.scss b/app/assets/stylesheets/gitlab_bootstrap.scss index b2bc4593a29..a1faf0601cb 100644 --- a/app/assets/stylesheets/gitlab_bootstrap.scss +++ b/app/assets/stylesheets/gitlab_bootstrap.scss @@ -1,31 +1,42 @@ -body { +body { margin-bottom:20px; } + +pre { + font-family:'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; + + &.dark { + background: #333; + color:#f5f5f5; + } +} + a { outline: none; color: $link_color; - &:hover { - text-decoration:none; + &:hover { + text-decoration:none; color: $blue_link; } - &.btn { + &.btn { color: $style_color; } - &.dark { + &.dark { color: $style_color; } - &.lined { - text-decoration:underlined; + &.lined { + text-decoration:underline; + &:hover { text-decoration:underline; } } - &.gray { + &.gray { color:gray; } - &.supp_diff_link { + &.supp_diff_link { text-align:center; padding:20px 0; background:#f1f1f1; @@ -38,24 +49,24 @@ a { } } -.neib { +.neib { margin-right:10px; } -.alert-message { +.alert-message { @extend .alert; - &.success { + &.success { @extend .alert-success; } - &.error { + &.error { @extend .alert-error; } } -.alert { - &.alert-well { +.alert { + &.alert-well { background:#ddd; border:1px solid #ccc; background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #ddd), to(#dfdfdf)); @@ -70,16 +81,12 @@ h3, h4, h5, h6 { line-height: 36px; } -h5 { +h5 { font-size:14px; } -code { - background:#FCEEC1; - color:$style_color; -} -table { +table { width:100%; th { padding-top: 9px; @@ -100,12 +107,12 @@ table { border-radius: 4px; } - &.zebra-striped { + &.zebra-striped { @extend .table-striped; } } -.btn { +.btn { background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f1f1f1), color-stop(25%, #f1f1f1), to(#e6e6e6)); background-image: -webkit-linear-gradient(#f1f1f1, #f1f1f1 25%, #e6e6e6); background-image: -moz-linear-gradient(top, #f1f1f1, #f1f1f1 25%, #e6e6e6); @@ -113,63 +120,63 @@ table { background-image: -o-linear-gradient(#f1f1f1, #f1f1f1 25%, #e6e6e6); background-image: linear-gradient(#f1f1f1, #f1f1f1 25%, #e6e6e6); - &:hover { + &:hover { } - &.btn-primary { + &.btn-primary { background:$link_color; border-color: #2A79A3; - &:hover { + &:hover { background:$blue_link; } } - &.primary { + &.primary { @extend .btn-primary; } - &.success { + &.success { color: #fff; text-shadow: 0 0 1px #111; background: #5bb75b;; font-weight: bold; - &:hover { + &:hover { background-color: #51a351; color: #fff; } } &.danger, - &.btn-danger { + &.btn-danger { color:#fff; background: #DA4E49; border-color: #BD362F; - &:hover { + &:hover { color:#fff; background: #EE4E49; } } - &.danger { + &.danger { @extend .btn-danger; } - &.small { + &.small { @extend .btn-small; } - &.active { + &.active { border-color:#aaa; background-color:#ccc; } } -a:focus { - outline: none; +a:focus { + outline: none; } -.nav-pills a:hover { +.nav-pills a:hover { background-color:#888; } @@ -177,20 +184,20 @@ a:focus { background-color: $style_color; } -.label { +.label { background-color: #474D57; - &.label-important { + &.label-important { background-color: #B94A48; } - &.label-issue { + &.label-issue { background-color: #eee; border: 1px solid #ccc; padding:4px 6px; color:#444; text-shadow:0 0 1px #fff; - &.grouped { + &.grouped { float: left; margin-right: 6px; padding: 6px; @@ -202,7 +209,7 @@ a:focus { color:$style_color; } -.nav-tabs > .active > a { +.nav-tabs > .active > a { font-weight:bold; } @@ -251,39 +258,39 @@ a:focus { margin-top:20px; } -.padded { +.padded { padding:20px; } -.ipadded { +.ipadded { padding:20px !important; } -.lborder { +.lborder { border-left:1px solid #eee; } -.borders { +.borders { border: 1px solid #ccc; @include shade; } -.no-borders { +.no-borders { border:none; } -table.no-borders { +table.no-borders { border:none; tr, td { border:none } } -.no-padding { +.no-padding { padding:0 !important; } -.underlined { +.underlined { border-bottom: 1px solid $border_color; } -.vlink { +.vlink { color: $link_color !important; } -.pretty_label { +.pretty_label { @include round-borders-all(4px); padding:2px 4px; background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8)); @@ -293,7 +300,7 @@ table.no-borders { color: #777; border: 1px solid #DEDFE1; - &.branch { + &.branch { border:none; font-size:13px; background: #474D57; @@ -303,70 +310,75 @@ table.no-borders { } } -.event_label { +.event_label { @extend .label; background-color: #999; - &.pushed { + &.pushed { background-color: #3A87AD; } - &.opened { + &.opened { background-color: #468847; } - &.closed { + &.closed { background-color: #B94A48; } - &.merged { + &.merged { background-color: #2A2; } } -img.avatar { +img.avatar { float:left; margin-right:15px; width:40px; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; + border:1px solid #ddd; + padding:1px; - &.s16 { + &.s16 { width:16px; + height:16px; } - &.s24 { + &.s24 { width:24px; + height:24px; + } + &.s32 { + width:32px; + height:32px; } } -img.lil_av { +img.lil_av { padding-left: 4px; padding-right:3px; } -form { +form { @extend .form-horizontal; - .actions { + .actions { @extend .form-actions; } - .clearfix { + .clearfix { @extend .control-group; } - .input { + .input { @extend .controls; } - label { + label { @extend .control-label; } - .xlarge { + .xlarge { @extend .input-xlarge; } - .xxlarge { + .xxlarge { @extend .input-xxlarge; } } @@ -375,26 +387,25 @@ form { * List li block element #1 * */ -.wll { +.wll { background-color: #FFF; padding: 10px 5px; min-height: 20px; border-bottom: 1px solid #eee; border-bottom: 1px solid rgba(0, 0, 0, 0.05); - cursor:pointer; - &.smoke { + &.smoke { background-color:#f5f5f5; } - &:hover { + &:hover { background:$hover; } &:last-child { border:none } p { padding-top:5px; margin:0; color:$style_color;} .author { color: #999; } - p { + p { color:#222; margin-bottom: 0; - img { + img { position:relative; top:3px; } @@ -406,7 +417,7 @@ form { * Block element #2 * */ -.entry { +.entry { position: relative; padding: 7px 15px; margin-bottom: 18px; @@ -428,10 +439,10 @@ form { border: 1px solid #ccc; - p { + p { color:$style_color; margin-bottom: 0; - img { + img { position:relative; top:3px; } @@ -443,66 +454,60 @@ form { * Big UI Block for show page content * */ -.ui-box { +.ui-box { background:#F9F9F9; margin-bottom: 25px; @include round-borders-all(4px); border-color: #CCC; + @include solid_shade; - ul { + ul { margin:0; } - h5, .title { + h5, .title { padding: 0 10px; @include round-borders-top(4px); + @include bg-gray-gradient; border-bottom: 1px solid #bbb; - background:#eee; - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); - background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); - background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); - background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); - &.small { + &.small { line-height: 28px; font-size: 14px; line-height:28px; text-shadow: 0 1px 1px white; } - form { + form { padding:9px 0; margin:0px; } - .nav-pills { - li { + .nav-pills { + li { padding:3px 0; &.active a { background-color:$style_color; } - a { + a { border-radius:7px; } } } } - .bottom { - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); - background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); - background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); - background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); + .bottom { + @include bg-gray-gradient; @include round-borders-bottom(4px); border-bottom:none; border-top: 1px solid #bbb; } - &.padded { - h5, .title { + &.padded { + h5, .title { margin: -20px; margin-bottom: 0; padding: 5px 20px; } - .middle_title { + .middle_title { background:#f5f5f5; margin:20px -20px; padding: 0 20px; @@ -512,22 +517,23 @@ form { color:#777; } } - .row_title { + .row_title { font-weight:bold; color:#444; - &:hover { + &:hover { + color:#444; text-decoration:underline; } } li, .wll { padding:10px; - &:first-child { + &:first-child { @include round-borders-top(4px); border-top:none; } - &:last-child { + &:last-child { @include round-borders-bottom(4px); border:none; } @@ -536,20 +542,17 @@ form { } table.admin-table { - @extend .table-bordered; + @extend .table-bordered; @extend .zebra-striped; - th { + @include solid_shade; + th { border-color: #CCC; border-bottom: 1px solid #bbb; - background:#eee; - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); - background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); - background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); - background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); + @include bg-gray-gradient; } } -.field_with_errors { +.field_with_errors { display:inline; } @@ -561,13 +564,13 @@ ul.breadcrumb { text-shadow: 0 1px 0 white } - a { + a { color:#474D57; font-weight:bold; font-size:14px; } - .arrow { + .arrow { background: url("images.png") no-repeat -85px -77px; width: 19px; height: 16px; @@ -579,22 +582,24 @@ ul.breadcrumb { } } -.nothing_here_message { +.nothing_here_message { text-align:center; padding:20px; color:#777; } /** - * UI box element + * UI box element * contains top, middle, bottom blocks - * + * */ -.main_box { +.main_box { @extend .borders; @extend .prepend-top-20; @extend .append-bottom-20; border-width:1px; + @include solid_shade; + img { max-width: 100%; } @@ -604,9 +609,9 @@ ul.breadcrumb { } } - .top_box_content, - .middle_box_content, - .bottom_box_content { + .top_box_content, + .middle_box_content, + .bottom_box_content { padding:15px; pre { @@ -617,7 +622,7 @@ ul.breadcrumb { } } - .middle_box_content { + .middle_box_content { border-radius:0; border:none; font-size:12px; @@ -626,20 +631,20 @@ ul.breadcrumb { border-top:1px solid #eee; } - .bottom_box_content { + .bottom_box_content { border-top:1px solid #eee; } } -input[type=text] { - &.large_text { +input[type=text] { + &.large_text { padding:6px; font-size:16px; } } -p { - &.slead { +p { + &.slead { color:#456; font-size:16px; margin-bottom: 12px; @@ -648,7 +653,7 @@ p { } } -h3.page_title { +h3.page_title { color:#456; font-size:20px; font-weight: normal; @@ -656,21 +661,17 @@ h3.page_title { } /** - * File content holder + * File content holder * */ -.file_holder { +.file_holder { border:1px solid #CCC; margin-bottom:1em; - @include shade; + @include solid_shade; - .file_title { + .file_title { border-bottom: 1px solid #bbb; - background:#eee; - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); - background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); - background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); - background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); + @include bg-gray-gradient; margin: 0; font-weight: normal; font-weight: bold; @@ -679,16 +680,16 @@ h3.page_title { padding: 9px 10px; height:18px; - .options { + .options { float:right; margin-top: -5px; } - .file_name { + .file_name { color:$style_color; font-size:14px; text-shadow: 0 1px 1px #fff; - small { + small { color:#999; font-size:13px; } @@ -698,21 +699,21 @@ h3.page_title { background:#fff; font-size: 11px; - &.wiki { + &.wiki { font-size: 13px; - code { + code { padding:0 4px; } padding:20px; - h1, h2 { - line-height: 46px; - } - h3, h4 { - line-height: 40px; - } + h1, h2 { + line-height: 46px; + } + h3, h4 { + line-height: 40px; + } } - &.image_file { + &.image_file { background:#eee; text-align:center; img { @@ -721,27 +722,27 @@ h3.page_title { } } - &.blob_file { + &.blob_file { } /** * Blame file */ - &.blame { - tr { + &.blame { + tr { border-bottom: 1px solid #eee; } - td { + td { padding:5px; } - .author, - .blame_commit { + .author, + .blame_commit { background:#f5f5f5; vertical-align:top; } - .lines { - pre { + .lines { + pre { padding:0; margin:0; background:none; @@ -750,27 +751,27 @@ h3.page_title { } } - &.logs { + &.logs { background:#eee; max-height: 700px; overflow-y: auto; - ol { + ol { margin-left:40px; padding: 10px 0; border-left: 1px solid #CCC; margin-bottom:0; background: white; - li { + li { color:#888; - p { + p { margin:0; color:#333; line-height:24px; padding-left: 10px; } - &:hover { + &:hover { background:$hover; } } @@ -780,7 +781,7 @@ h3.page_title { /** * Code file */ - &.code { + &.code { padding:0; td.code { width: 100%; diff --git a/app/assets/stylesheets/jquery_ui.scss b/app/assets/stylesheets/jquery_ui.scss deleted file mode 100644 index 1063f1d080e..00000000000 --- a/app/assets/stylesheets/jquery_ui.scss +++ /dev/null @@ -1,33 +0,0 @@ -/** - * JQUERY UI datepicker - * - */ -.ui-datepicker { - border-color:#eee; - padding:20px; - - .ui-state-default { - background:#f1f1f1; - padding:5px; - } - .ui-state-active { - background:#fff; - } -} - -/** - * JQUERY UI progressbar - * - */ -.ui-progressbar { - border:1px solid #ddd; - height:6px; - margin:0; - padding:0; - - .ui-progressbar-value { - background-color: #62C462;//$blue_link; - margin:0; - } -} - diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss index 5f13f301f35..b4f0ebf8ba0 100644 --- a/app/assets/stylesheets/main.scss +++ b/app/assets/stylesheets/main.scss @@ -3,8 +3,8 @@ /** GITLAB colors **/ $text_color:#222; -$lite_text_color: #666; -$link_color:#2A79A3; +$lite_text_color: #666; +$link_color:#2A79A3; $active_link_color:#2FA0BB; $active_bg_color:#79C3E0; $active_bd_color: #2FA0BB; @@ -23,6 +23,8 @@ $blue_link: #2fa0bb; $style_color: #474D57; $hover: #FDF5D9; +/** GITLAB Fonts **/ +@font-face { font-family: Korolev; src: url('korolev-medium-compressed.otf'); } /** MIXINS **/ @mixin shade { @@ -31,6 +33,12 @@ $hover: #FDF5D9; box-shadow: 0 0 3px #ddd; } +@mixin solid_shade { + -moz-box-shadow: 0 0 0 3px #eee; + -webkit-box-shadow: 0 0 0 3px #eee; + box-shadow: 0 0 0 3px #eee; +} + @mixin border-radius($radius) { -moz-border-radius: $radius; -webkit-border-radius: $radius; @@ -64,24 +72,30 @@ $hover: #FDF5D9; border-radius: $radius; } - +@mixin bg-gray-gradient { + background:#eee; + background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); + background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); + background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); + background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); +} /** - * Header of application. + * Header of application. * Contain application logo, search panel, profile icon */ -@import "header.scss"; +@import "sections/header.scss"; /** - * Navigation menu of application. + * Navigation menu of application. * Panel with links to pages depends on project, profile or admin area */ -@import "nav.scss"; +@import "sections/nav.scss"; /** - * This file represent some UI that can be changed - * during web app restyle or theme select. - * + * This file represent some UI that can be changed + * during web app restyle or theme select. + * * Next items should be placed there * - link, button colors * - header restyles @@ -112,7 +126,7 @@ $hover: #FDF5D9; * Most of application styles placed here. * This file represent common UI that should not be changed between themes * or project restyling like form width or user avatar class or commit title - * + * * TODO: clean it */ @import "common.scss"; @@ -134,19 +148,19 @@ $hover: #FDF5D9; @import "ref_select.scss"; /** - * Code (files list) styles. Browsing project files there + * Code (files list) styles. Browsing project files there */ @import "sections/tree.scss"; /** - * This file represent notes(comments) styles + * This file represent notes(comments) styles */ -@import "notes.scss"; +@import "sections/notes.scss"; /** - * Devise styles + * Devise styles */ -@import "login.scss"; +@import "sections/login.scss"; /** * CODE HIGHTLIGHT BASE @@ -159,9 +173,3 @@ $hover: #FDF5D9; * */ @import "highlight/dark.scss"; - -/** - * JQUERY UI ext - * - */ -@import "jquery_ui.scss"; diff --git a/app/assets/stylesheets/ref_select.scss b/app/assets/stylesheets/ref_select.scss index 6f6a1bc983d..5b52e11b355 100644 --- a/app/assets/stylesheets/ref_select.scss +++ b/app/assets/stylesheets/ref_select.scss @@ -33,9 +33,7 @@ } .chzn-single { - background:#ddd; - //border:none; - //box-shadow:none; + @include bg-gray-gradient; div { background:transparent; diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss index 6052ec3fabb..e2db701db71 100644 --- a/app/assets/stylesheets/sections/commits.scss +++ b/app/assets/stylesheets/sections/commits.scss @@ -194,4 +194,16 @@ float:right; @extend .cgray; } + + code { + background:#FCEEC1; + color:$style_color; + } + + .commit_short_id { + float:left; + @extend .lined; + min-width:65px; + font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; + } } diff --git a/app/assets/stylesheets/sections/graph.scss b/app/assets/stylesheets/sections/graph.scss index 33d91de5391..2aa4463e45e 100644 --- a/app/assets/stylesheets/sections/graph.scss +++ b/app/assets/stylesheets/sections/graph.scss @@ -6,11 +6,7 @@ h4 { padding:0 10px; border-bottom: 1px solid #bbb; - background:#eee; - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); - background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); - background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); - background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); + @include bg-gray-gradient; } .graph { diff --git a/app/assets/stylesheets/header.scss b/app/assets/stylesheets/sections/header.scss index c3a570036bb..d0fb662e69e 100644 --- a/app/assets/stylesheets/header.scss +++ b/app/assets/stylesheets/sections/header.scss @@ -2,14 +2,14 @@ * Application Header * */ -header { +header { width:100%; padding:0; margin:0; top:1px; left:0; background: #F1F1F1; /* for non-css3 browsers */ - border-bottom: 1px solid #ccc; + border-bottom: 1px solid #ccc; box-shadow: 0 -1px 0 white inset; -moz-box-shadow: 0 -1px 0 white inset; -webkit-box-shadow: 0 -1px 0 white inset; @@ -17,7 +17,7 @@ header { height:60px; /** - * + * * Logo holder * */ @@ -26,23 +26,25 @@ header { float:left; position:relative; top:-5px; - - a { + a { float:left; - h1 { - text-indent:-9999px; + h1 { + padding-top: 5px; width:102px; - background: url('logo_text.png') no-repeat 0px -3px; + background: url('logo_dark.png') no-repeat 0px -3px; float:left; margin-left:5px; - font-size:20px; + font-size:36px; line-height:36px; - font-weight:bold; - color:#aaa; + font-weight:normal; + color:$style_color; text-shadow: 0 1px 1px #FFF; padding-left:50px; + height:40px; + font-family: 'Korolev', sans-serif; } + } .separator { margin-left:20px; @@ -54,8 +56,8 @@ header { margin-top: -10px; } } - .container { - .top_panel_content { + .container { + .top_panel_content { margin:auto; position:relative; padding:15px 0; @@ -63,25 +65,27 @@ header { } /** - * + * * Project / Area name * */ .project_name { + position:relative; float:left; margin:0; margin-right:30px; - font-size:24px; + font-size:36px; line-height:36px; - font-weight:500; + font-weight:normal; color:$style_color; text-shadow: 0 1px 1px #FFF; + font-family: 'Korolev', sans-serif; } - .fbtn { + .fbtn { float: right; margin-right:10px; - .btn { + .btn { margin-left:7px; background: #F1F1F1; border: 1px solid #CCC; @@ -90,13 +94,13 @@ header { /** - * + * * Search box * */ - .search { + .search { float: right; - margin-right: 50px; + margin-right: 45px; .search-input { @extend .span2; @@ -110,7 +114,7 @@ header { } /** - * + * * Account box * */ @@ -125,16 +129,13 @@ header { display: block; cursor: pointer; img { - -moz-box-shadow: 0 0 5px #ccc; - -webkit-box-shadow: 0 0 5px #ccc; - box-shadow: 0 0 5px #ccc; - border-radius: 4px; + @include border-radius(4px); right: 5px; position: absolute; - width: 31px; - height: 31px; + width: 28px; + height: 28px; display: block; - top: 0; + top: 2px; &:after { content: " "; display: block; @@ -189,7 +190,7 @@ header { width: 100px; position: absolute; right: 10px; - top: 46px; + top: 42px; margin-top: 0; float: right; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss index dd1c22d4e76..1b61ec3fe85 100644 --- a/app/assets/stylesheets/sections/issues.scss +++ b/app/assets/stylesheets/sections/issues.scss @@ -30,13 +30,72 @@ .issue { padding:7px 10px; + .issue_check { + float:left; + padding: 8px 0; + padding-right: 8px; + min-width: 15px; + } + + p { + padding-top:0; + padding-bottom:2px; + } + img.avatar { width:32px; margin-top:4px; } - p.row_title { - padding:0px; - padding-bottom:2px; + } +} + +input.check_all_issues { + float:left; + padding: 0; + margin:0; + margin-right: 10px; + position: relative; + top: 8px; + height: 22px; +} + +.issues_content { + .title { + height: 40px; + } +} + +#issues-table-holder { + .issues_filters { + form { + padding:0; + margin:0; + margin-top:7px + } + } + + .issues_bulk_update { + margin: 0; + form { + padding:0; + margin:0; + margin-top:7px + } + .update_selected_issues { + position:relative; + top:-2px; + margin-left:4px; + float:left; + } + + .update_issues_text { + padding:3px; + line-height: 18px; + float:left; } } } + +#update_status { + width:100px; +} diff --git a/app/assets/stylesheets/login.scss b/app/assets/stylesheets/sections/login.scss index 3bba7062a24..5b8763cfec0 100644 --- a/app/assets/stylesheets/login.scss +++ b/app/assets/stylesheets/sections/login.scss @@ -27,6 +27,7 @@ body.login-page{ -moz-border-radius-topright: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; + margin-bottom:0px; } .login-box input.text.bottom{ @@ -41,4 +42,3 @@ body.login-page{ } .login-box a.forgot{float: right; padding-top: 6px} - diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss index 34f43acf839..ec84a64e23a 100644 --- a/app/assets/stylesheets/sections/merge_requests.scss +++ b/app/assets/stylesheets/sections/merge_requests.scss @@ -94,3 +94,8 @@ li.merge_request { padding-bottom: 2px; } } + +.merge_in_progress { + @extend .padded; + @extend .append-bottom-10; +} diff --git a/app/assets/stylesheets/nav.scss b/app/assets/stylesheets/sections/nav.scss index 93df41939a7..fc7293b2864 100644 --- a/app/assets/stylesheets/nav.scss +++ b/app/assets/stylesheets/sections/nav.scss @@ -6,14 +6,11 @@ ul.main_menu { border-radius: 4px; margin: auto; margin:30px 0; - background:#eee; border:1px solid #bbb; height:37px; - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); - background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); - background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); - background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); + @include bg-gray-gradient; position:relative; + overflow:hidden; @include shade; .count { position: relative; diff --git a/app/assets/stylesheets/notes.scss b/app/assets/stylesheets/sections/notes.scss index 39db704b1a9..30587ef5b63 100644 --- a/app/assets/stylesheets/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -14,7 +14,8 @@ border-bottom:1px solid #aaa; } -.issue_notes { +.issue_notes, +.wiki_notes { .note_content { float:left; width:400px; @@ -23,8 +24,8 @@ /* Note textare */ #note_note { - height:100px; - width:97%; + height:80px; + width:99%; font-size:14px; } @@ -37,21 +38,31 @@ } } -.note .delete-note { - display:none; - float:right; +.note { + padding: 8px 0; + border-bottom: 1px solid #eee; + overflow: hidden; + display: block; + img {float: left; margin-right: 10px;} + .note-author cite{font-style: italic;} + p { color:$style_color; } + .note-author { color: $style_color;} + + .note-title { margin-left:45px; padding-top: 5px;} + .avatar { + margin-top:3px; + } + + .delete-note { + display:none; + float:right; + } + + &:hover { + .delete-note { display:block; } + } } -.note:hover .delete-note { display:block; } -.note {padding: 10px 0; border-bottom: 1px solid #eee; overflow: hidden; display: block;} -.note img{float: left; margin-right: 10px;} -.note span.note-title{display: block;} -.note span.note-title{margin-bottom: 10px} -.note span.note-author{color: #999; font-weight: normal; font-style: italic;} -.note span.note-author strong{font-weight: bold; font-style: normal;} -.note p { color:$style_color; } -.note .note-author { color: $style_color;} - -.note .note-title { margin-left:55px; } + p.notify_controls input{ margin: 5px; @@ -99,8 +110,25 @@ tr.line_notes_row { td { border-bottom:1px solid #ddd; } - .actions { + .note_actions { margin:0; + padding-top: 10px; + + .buttons { + float:left; + width:300px; + } + .options { + .labels { + float:left; + padding-left:10px; + label { + padding: 6px 0; + margin: 0; + width:120px; + } + } + } } } @@ -141,23 +169,38 @@ td .line_note_link { margin: 0; } - .file_upload { - position: absolute; - right:14px; - top:7px; + .note_advanced_opts { + h6 { + line-height: 32px; + padding-right: 15px; + } } - div.attachments { + .attachments { position:relative; width: 350px; - height: 36px; + height: 50px; overflow:hidden; margin:0 0 5px !important; - } - .file_name { - line-height:30px; - width:240px; - height:28px; - overflow:hidden; + + .input_file { + .file_upload { + position: absolute; + right:14px; + top:7px; + } + + .file_name { + line-height:30px; + width:240px; + height:28px; + overflow:hidden; + } + .input-file { + width: 260px; + height: 41px; + float: right; + } + } } } diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss index 8c79e45e703..0866b43f71d 100644 --- a/app/assets/stylesheets/sections/projects.scss +++ b/app/assets/stylesheets/sections/projects.scss @@ -1,17 +1,18 @@ -.projects { +.projects { @extend .row; .activities { } - .side { + .side { @extend .span4; @extend .right; - .projects_box { - h5 { + .projects_box { + h5 { color:$style_color; font-size:16px; text-shadow: 0 1px 1px #fff; + padding: 2px 10px; } @extend .leftbar; @extend .ui-box; @@ -19,21 +20,22 @@ } } -.new_project, -.edit_project { - .project_name_holder { +.new_project, +.edit_project { + .project_name_holder { input, - label { + label { font-size:16px; line-height:20px; padding:8px; } - label { + label { color:#888; } - .btn { + .btn { padding:6px; margin-left:10px; + margin-bottom:8px; } } } diff --git a/app/assets/stylesheets/sections/tree.scss b/app/assets/stylesheets/sections/tree.scss index 072d6103c8d..891f5e20871 100644 --- a/app/assets/stylesheets/sections/tree.scss +++ b/app/assets/stylesheets/sections/tree.scss @@ -38,9 +38,7 @@ .tree-item { .tree-item-file-name { vertical-align:middle; - font-weight:bold; a { - color:$style_color; &:hover { color:$blue_link; } @@ -55,7 +53,7 @@ #tree-slider { - @include shade; + @include solid_shade; width:100%; border-color:#ccc; @@ -74,11 +72,7 @@ th { border-color: #CCC; border-bottom: 1px solid #bbb; - background:#eee; - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); - background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); - background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); - background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); + @include bg-gray-gradient; } } diff --git a/app/assets/stylesheets/themes/ui_basic.scss b/app/assets/stylesheets/themes/ui_basic.scss index 1b731c9192b..cf5eda1c893 100644 --- a/app/assets/stylesheets/themes/ui_basic.scss +++ b/app/assets/stylesheets/themes/ui_basic.scss @@ -1,18 +1,50 @@ /** - * This file represent some UI that can be changed - * during web app restyle or theme select. + * This file represent some UI that can be changed + * during web app restyle or theme select. * */ -.ui_basic { +.ui_basic { /* * Common styles * */ a { color: $link_color; - &:hover { - text-decoration:none; + &:hover { + text-decoration:none; color: $blue_link; } } + + header { + .fbtn { + .btn { + background-color: #F8F8F8; + background-image: -webkit-gradient(linear,left top,left bottom,from(#F8F8F8),to(#ECECEC)); + background-image: -webkit-linear-gradient(top,#F8F8F8,#ECECEC); + background-image: -moz-linear-gradient(top,#F8F8F8,#ECECEC); + background-image: -ms-linear-gradient(top,#F8F8F8,#ECECEC); + background-image: -o-linear-gradient(top,#F8F8F8,#ECECEC); + background-image: linear-gradient(top,#F8F8F8,#ECECEC); + filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#f8f8f8',EndColorStr='#ececec'); + border-color: #C6C6C6; + margin-left:7px; + @include border-radius(3px); + box-shadow:none; + color:#666; + } + } + .search { + .search-input { + @include border-radius(3px); + border-color: #C6C6C6; + box-shadow:none; + } + } + .pic { + img { + @include border-radius(3px); + } + } + } } diff --git a/app/assets/stylesheets/themes/ui_mars.scss b/app/assets/stylesheets/themes/ui_mars.scss index 0fea6144431..c630f388945 100644 --- a/app/assets/stylesheets/themes/ui_mars.scss +++ b/app/assets/stylesheets/themes/ui_mars.scss @@ -1,7 +1,7 @@ /** - * This file represent some UI that can be changed - * during web app restyle or theme select. - * + * This file represent some UI that can be changed + * during web app restyle or theme select. + * * Next items should be placed there * - link colors * - header restyles @@ -13,25 +13,33 @@ * Application Header * */ - header { + header { background: #474D57 url('bg-header.png') repeat-x bottom; box-shadow:none; border-bottom: 1px solid #444; - .fbtn { - .btn { + .fbtn { + .btn { + i { + position: relative; + top: 1px; + } margin-left:8px; background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #595D63), to(#31363E)); background-image: -webkit-linear-gradient(#595D63 6.6%, #31363E); background-image: -moz-linear-gradient(#595D63 6.6%, #31363E); background-image: -o-linear-gradient(#595D63 6.6%, #31363E); font-size: 12px; - &:hover { + &:hover { background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #595D63), to(#2C2F35)); background-image: -webkit-linear-gradient(#595D63 6.6%, #2C2F35); background-image: -moz-linear-gradient(#595D63 6.6%, #202227); background-image: -o-linear-gradient(#595D63 6.6%, #202227); background-position:0 0; + color:#fff; + i { + @extend .icon-white; + } } border: 1px solid #31363E; @@ -39,10 +47,10 @@ text-shadow: 0 -1px 0 #000000; } } - .search { + .search { float: right; - margin-right: 55px; - .search-input { + margin-right: 45px; + .search-input { border: 1px solid rgba(0, 0, 0, 0.7); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.2), 0 2px 2px rgba(0, 0, 0, 0.4) inset; background-color: #D2D5DA; @@ -57,26 +65,19 @@ color: #666; } .app_logo { - a { - h1 { - background: url('images.png') no-repeat -3px -6px; - width: 65px; - height: 26px; - margin: 6px 0; - padding: 0; - float: left; - text-indent: -1000em; - float:left; + a { + h1 { + background: url('logo_white.png') no-repeat 0px -3px; + color:#fff; + text-shadow: 0 1px 1px #111; } } .separator { - border-color:#444; - background:#31363E; + display:none; } } .project_name { - line-height:38px; color:#fff; text-shadow: 0 1px 1px #111; } diff --git a/app/assets/stylesheets/themes/ui_modern.scss b/app/assets/stylesheets/themes/ui_modern.scss index 1aeaafb7056..1f0d795562b 100644 --- a/app/assets/stylesheets/themes/ui_modern.scss +++ b/app/assets/stylesheets/themes/ui_modern.scss @@ -1,69 +1,134 @@ /** - * This file represent some UI that can be changed - * during web app restyle or theme select. - * + * This file represent some UI that can be changed + * during web app restyle or theme select. + * * Next items should be placed there * - link colors * - header styles * - main menu styles * */ -.ui_modern { - ul.main_menu { - background:none; - box-shadow:none; - @include border-radius(0px); - border:none; - border-bottom:2px solid #456; +.ui_modern { + /* + * Application Header + * + */ + header { + height:40px; + background-image: -moz-linear-gradient(top, #333, #222); + background-image: -ms-linear-gradient(top, #333, #222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333), to(#222)); + background-image: -webkit-linear-gradient(top, #333, #222); + background-image: -o-linear-gradient(top, #333, #222); + background-image: linear-gradient(top, #333, #222); + background-repeat: repeat-x; + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + + .container .top_panel_content { padding: 5px 0; } - li { - border:none; - &.current { - border-bottom:2px solid #f90; - background-color:#fff; - position:relative; - top:2px; + /** + * + * Logo holder + * + */ + .app_logo { + width:160px; + a { + h1 { + background: none; + color:#DDD; + font-size:30px; + text-shadow: 0 1px 1px #111; + padding-left: 0; + } + } + .separator { + width: 1px; + height: 40px; + margin: 0 10px; + overflow: hidden; + background: #222; + border-left: 1px solid #333; } } - } - /* - * Common styles - * - */ - a { - color: #E28934; - &:hover { - text-decoration:none; - color: #f90; + .fbtn { + .btn { + i { + position: relative; + top: 2px; + } + background:none; + margin-left:8px; + font-size: 13px; + line-height: 19px; + color:#ccc; + &:hover { + color:#fff; + i { + @extend .icon-white; + } + } + border: none; + box-shadow:none; + text-shadow: 0 -1px 0 #000000; + border-left: 1px solid #333; + } } - } - .btn { - &.primary, - &.btn-primary { - border-color:#C60; - background:#D70; + /** + * + * Search box + * + */ + .search { + float: right; + margin-right: 45px; + .search-input { + border: 1px solid rgba(0, 0, 0, 0.7); + box-shadow: 0 1px 0 rgba(255, 255, 255, 0.2), 0 2px 2px rgba(0, 0, 0, 0.4) inset; + background-color: #D2D5DA; + background-color: rgba(255, 255, 255, 0.5); - &:hover { - background:#F90; + &:focus { + background-color: white; + } + } + .search-input::-webkit-input-placeholder { + color: #666; } } - } - - .alert-info { - border-color:#FDA; - background:#FED; - color:#D70; - } - - .progress .bar { - background:#D80; - } + /** + * + * Project / Area name + * + */ + .project_name { + line-height:36px; + font-size:30px; + color:#DDD; + text-shadow: 0 1px 1px #111; + } - .back_link { - color:#D80; + /** + * + * Account box + * + */ + .account-box { + top:6px; + img { + top:1px; + right: 5px; + width: 26px; + height: 26px; + } + } } } diff --git a/app/contexts/base_context.rb b/app/contexts/base_context.rb new file mode 100644 index 00000000000..101be50d54b --- /dev/null +++ b/app/contexts/base_context.rb @@ -0,0 +1,20 @@ +class BaseContext + attr_accessor :project, :current_user, :params + + def initialize(project, user, params) + @project, @current_user, @params = project, user, params.dup + end + + def abilities + @abilities ||= begin + abilities = Six.new + abilities << Ability + abilities + end + end + + def can?(object, action, subject) + abilities.allowed?(object, action, subject) + end +end + diff --git a/app/contexts/commit_load.rb b/app/contexts/commit_load.rb new file mode 100644 index 00000000000..81fb4925cc8 --- /dev/null +++ b/app/contexts/commit_load.rb @@ -0,0 +1,33 @@ +class CommitLoad < BaseContext + def execute + result = { + commit: nil, + suppress_diff: false, + line_notes: [], + notes_count: 0, + note: nil, + status: :ok + } + + commit = project.commit(params[:id]) + + if commit + commit = CommitDecorator.decorate(commit) + line_notes = project.commit_line_notes(commit) + + result[:commit] = commit + result[:note] = project.build_commit_note(commit) + result[:line_notes] = line_notes + result[:notes_count] = line_notes.count + project.commit_notes(commit).count + + begin + result[:suppress_diff] = true if commit.diffs.size > 200 && !params[:force_show_diff] + rescue Grit::Git::GitTimeout + result[:suppress_diff] = true + result[:status] = :huge_commit + end + end + + result + end +end diff --git a/app/contexts/issues_bulk_update_context.rb b/app/contexts/issues_bulk_update_context.rb new file mode 100644 index 00000000000..7c3c1d4f7c3 --- /dev/null +++ b/app/contexts/issues_bulk_update_context.rb @@ -0,0 +1,24 @@ +class IssuesBulkUpdateContext < BaseContext + def execute + update_data = params[:update] + + issues_ids = update_data[:issues_ids].split(",") + milestone_id = update_data[:milestone_id] + assignee_id = update_data[:assignee_id] + status = update_data[:status] + + opts = {} + opts[:milestone_id] = milestone_id if milestone_id.present? + opts[:assignee_id] = assignee_id if assignee_id.present? + opts[:closed] = (status == "closed") if status.present? + + issues = Issue.where(id: issues_ids).all + issues = issues.select { |issue| can?(current_user, :modify_issue, issue) } + issues.each { |issue| issue.update_attributes(opts) } + { + count: issues.count, + success: !issues.count.zero? + } + end +end + diff --git a/app/contexts/merge_requests_load.rb b/app/contexts/merge_requests_load.rb new file mode 100644 index 00000000000..6778db3bce5 --- /dev/null +++ b/app/contexts/merge_requests_load.rb @@ -0,0 +1,16 @@ +class MergeRequestsLoad < BaseContext + def execute + type = params[:f].to_i + + merge_requests = project.merge_requests + + merge_requests = case type + when 1 then merge_requests + when 2 then merge_requests.closed + when 3 then merge_requests.opened.assigned(current_user) + else merge_requests.opened + end.page(params[:page]).per(20) + + merge_requests.includes(:author, :project).order("closed, created_at desc") + end +end diff --git a/app/contexts/notes/create_context.rb b/app/contexts/notes/create_context.rb new file mode 100644 index 00000000000..d93adb835ef --- /dev/null +++ b/app/contexts/notes/create_context.rb @@ -0,0 +1,12 @@ +module Notes + class CreateContext < BaseContext + def execute + note = project.notes.new(params[:note]) + note.author = current_user + note.notify = true if params[:notify] == '1' + note.notify_author = true if params[:notify_author] == '1' + note.save + note + end + end +end diff --git a/app/contexts/notes/load_context.rb b/app/contexts/notes/load_context.rb new file mode 100644 index 00000000000..c89a7d19761 --- /dev/null +++ b/app/contexts/notes/load_context.rb @@ -0,0 +1,34 @@ +module Notes + class LoadContext < BaseContext + def execute + target_type = params[:target_type] + target_id = params[:target_id] + first_id = params[:first_id] + last_id = params[:last_id] + + + @notes = case target_type + when "commit" + then project.commit_notes(project.commit(target_id)).fresh.limit(20) + when "snippet" + then project.snippets.find(target_id).notes + when "wall" + then project.common_notes.order("created_at DESC").fresh.limit(50) + when "issue" + then project.issues.find(target_id).notes.inc_author.order("created_at DESC").limit(20) + when "merge_request" + then project.merge_requests.find(target_id).notes.inc_author.order("created_at DESC").limit(20) + when "wiki" + then project.wikis.reverse.map {|w| w.notes.fresh }.flatten[0..20] + end + + @notes = if last_id + @notes.where("id > ?", last_id) + elsif first_id + @notes.where("id < ?", first_id) + else + @notes + end + end + end +end diff --git a/app/contexts/test_hook_context.rb b/app/contexts/test_hook_context.rb new file mode 100644 index 00000000000..cba5d1f87c2 --- /dev/null +++ b/app/contexts/test_hook_context.rb @@ -0,0 +1,8 @@ +class TestHookContext < BaseContext + def execute + hook = project.hooks.find(params[:id]) + commits = project.commits(project.default_branch, nil, 3) + data = project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", current_user) + hook.execute(data) + end +end diff --git a/app/controllers/admin/hooks_controller.rb b/app/controllers/admin/hooks_controller.rb new file mode 100644 index 00000000000..7f832fd5697 --- /dev/null +++ b/app/controllers/admin/hooks_controller.rb @@ -0,0 +1,44 @@ +class Admin::HooksController < ApplicationController + layout "admin" + before_filter :authenticate_user! + before_filter :authenticate_admin! + + def index + @hooks = SystemHook.all + @hook = SystemHook.new + end + + def create + @hook = SystemHook.new(params[:hook]) + + if @hook.save + redirect_to admin_hooks_path, notice: 'Hook was successfully created.' + else + @hooks = SystemHook.all + render :index + end + end + + def destroy + @hook = SystemHook.find(params[:id]) + @hook.destroy + + redirect_to admin_hooks_path + end + + + def test + @hook = SystemHook.find(params[:hook_id]) + data = { + event_name: "project_create", + name: "Ruby", + path: "ruby", + project_id: 1, + owner_name: "Someone", + owner_email: "example@gitlabhq.com" + } + @hook.execute(data) + + redirect_to :back + end +end diff --git a/app/controllers/admin/mailer_controller.rb b/app/controllers/admin/mailer_controller.rb deleted file mode 100644 index 2352e189204..00000000000 --- a/app/controllers/admin/mailer_controller.rb +++ /dev/null @@ -1,45 +0,0 @@ -class Admin::MailerController < ApplicationController - layout "admin" - before_filter :authenticate_user! - before_filter :authenticate_admin! - - def preview - - end - - def preview_note - @note = Note.first - @user = @note.author - @project = @note.project - case params[:type] - when "Commit" then - @commit = @project.commit - render :file => 'notify/note_commit_email', :layout => 'notify' - when "Issue" then - @issue = Issue.first - render :file => 'notify/note_issue_email', :layout => 'notify' - else - render :file => 'notify/note_wall_email', :layout => 'notify' - end - rescue - render :text => "Preview not available" - end - - def preview_user_new - @user = User.first - @password = "DHasJKDHAS!" - - render :file => 'notify/new_user_email', :layout => 'notify' - rescue - render :text => "Preview not available" - end - - def preview_issue_new - @issue = Issue.first - @user = @issue.assignee - @project = @issue.project - render :file => 'notify/new_issue_email', :layout => 'notify' - rescue - render :text => "Preview not available" - end -end diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb index 0ff97bf2c32..80d11f03ef0 100644 --- a/app/controllers/admin/projects_controller.rb +++ b/app/controllers/admin/projects_controller.rb @@ -2,6 +2,7 @@ class Admin::ProjectsController < ApplicationController layout "admin" before_filter :authenticate_user! before_filter :authenticate_admin! + before_filter :admin_project, only: [:edit, :show, :update, :destroy, :team_update] def index @admin_projects = Project.scoped @@ -10,13 +11,9 @@ class Admin::ProjectsController < ApplicationController end def show - @admin_project = Project.find_by_code(params[:id]) - - @users = if @admin_project.users.empty? - User - else - User.not_in_project(@admin_project) - end.all + @users = User.scoped + @users = @users.not_in_project(@admin_project) if @admin_project.users.present? + @users = @users.all end def new @@ -24,19 +21,10 @@ class Admin::ProjectsController < ApplicationController end def edit - @admin_project = Project.find_by_code(params[:id]) end def team_update - @admin_project = Project.find_by_code(params[:id]) - - UsersProject.bulk_import( - @admin_project, - params[:user_ids], - params[:project_access] - ) - - @admin_project.update_repository + @admin_project.add_users_ids_to_team(params[:user_ids], params[:project_access]) redirect_to [:admin, @admin_project], notice: 'Project was successfully updated.' end @@ -48,13 +36,11 @@ class Admin::ProjectsController < ApplicationController if @admin_project.save redirect_to [:admin, @admin_project], notice: 'Project was successfully created.' else - render :action => "new" + render action: "new" end end def update - @admin_project = Project.find_by_code(params[:id]) - owner_id = params[:project].delete(:owner_id) if owner_id @@ -64,14 +50,19 @@ class Admin::ProjectsController < ApplicationController if @admin_project.update_attributes(params[:project]) redirect_to [:admin, @admin_project], notice: 'Project was successfully updated.' else - render :action => "edit" + render action: "edit" end end def destroy - @admin_project = Project.find_by_code(params[:id]) @admin_project.destroy redirect_to admin_projects_url, notice: 'Project was successfully deleted.' end + + private + + def admin_project + @admin_project = Project.find_by_code(params[:id]) + end end diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 4b123e4f032..1e8f420b098 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -34,7 +34,7 @@ class Admin::UsersController < ApplicationController def new - @admin_user = User.new(:projects_limit => Gitlab.config.default_projects_limit) + @admin_user = User.new(projects_limit: Gitlab.config.default_projects_limit) end def edit diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3265046d2ae..7c1941ec859 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -4,21 +4,22 @@ class ApplicationController < ActionController::Base before_filter :set_current_user_for_mailer before_filter :check_token_auth before_filter :set_current_user_for_observers + before_filter :dev_tools if Rails.env == 'development' protect_from_forgery helper_method :abilities, :can? rescue_from Gitlab::Gitolite::AccessDenied do |exception| - render "errors/gitolite", :layout => "error" + render "errors/gitolite", layout: "error" end rescue_from Encoding::CompatibilityError do |exception| - render "errors/encoding", :layout => "error", :status => 404 + render "errors/encoding", layout: "error", status: 404 end rescue_from ActiveRecord::RecordNotFound do |exception| - render "errors/not_found", :layout => "error", :status => 404 + render "errors/not_found", layout: "error", status: 404 end layout :layout_by_resource @@ -96,15 +97,15 @@ class ApplicationController < ActionController::Base end def access_denied! - render "errors/access_denied", :layout => "error", :status => 404 + render "errors/access_denied", layout: "error", status: 404 end def not_found! - render "errors/not_found", :layout => "error", :status => 404 + render "errors/not_found", layout: "error", status: 404 end def git_not_found! - render "errors/git_not_found", :layout => "error", :status => 404 + render "errors/git_not_found", layout: "error", status: 404 end def method_missing(method_sym, *arguments, &block) @@ -126,7 +127,7 @@ class ApplicationController < ActionController::Base end def render_404 - render :file => File.join(Rails.root, "public", "404"), :layout => false, :status => "404" + render file: File.join(Rails.root, "public", "404"), layout: false, status: "404" end def require_non_empty_project @@ -142,4 +143,8 @@ class ApplicationController < ActionController::Base def render_full_content @full_content = true end + + def dev_tools + Rack::MiniProfiler.authorize_request + end end diff --git a/app/controllers/commits_controller.rb b/app/controllers/commits_controller.rb index 25e980e017b..717912d9e92 100644 --- a/app/controllers/commits_controller.rb +++ b/app/controllers/commits_controller.rb @@ -9,7 +9,7 @@ class CommitsController < ApplicationController before_filter :authorize_read_project! before_filter :authorize_code_access! before_filter :require_non_empty_project - before_filter :load_refs, :only => :index # load @branch, @tag & @ref + before_filter :load_refs, only: :index # load @branch, @tag & @ref before_filter :render_full_content def index @@ -17,52 +17,44 @@ class CommitsController < ApplicationController @limit, @offset = (params[:limit] || 40), (params[:offset] || 0) @commits = @project.commits(@ref, params[:path], @limit, @offset) + @commits = CommitDecorator.decorate(@commits) respond_to do |format| format.html # index.html.erb format.js - format.atom { render :layout => false } + format.atom { render layout: false } end end def show - @commit = project.commit(params[:id]) - - git_not_found! and return unless @commit - - @commit = CommitDecorator.decorate(@commit) - - @note = @project.build_commit_note(@commit) - @comments_allowed = true - @line_notes = project.commit_line_notes(@commit) - - @notes_count = @line_notes.count + project.commit_notes(@commit).count + result = CommitLoad.new(project, current_user, params).execute + + @commit = result[:commit] + + if @commit + @suppress_diff = result[:suppress_diff] + @note = result[:note] + @line_notes = result[:line_notes] + @notes_count = result[:notes_count] + @comments_allowed = true + else + return git_not_found! + end - if @commit.diffs.size > 200 && !params[:force_show_diff] - @suppress_diff = true + if result[:status] == :huge_commit + render "huge_commit" and return end - rescue Grit::Git::GitTimeout - render "huge_commit" end def compare - first = project.commit(params[:to].try(:strip)) - last = project.commit(params[:from].try(:strip)) + result = Commit.compare(project, params[:from], params[:to]) - @diffs = [] - @commits = [] + @commits = result[:commits] + @commit = result[:commit] + @diffs = result[:diffs] @line_notes = [] - if first && last - commits = [first, last].sort_by(&:created_at) - younger = commits.first - older = commits.last - - - @commits = project.repo.commits_between(younger.id, older.id).map {|c| Commit.new(c)} - @diffs = project.repo.diff(younger.id, older.id) rescue [] - @commit = Commit.new(older) - end + @commits = CommitDecorator.decorate(@commits) end def patch @@ -70,9 +62,9 @@ class CommitsController < ApplicationController send_data( @commit.to_patch, - :type => "text/plain", - :disposition => 'attachment', - :filename => (@commit.id.to_s + ".patch") + type: "text/plain", + disposition: 'attachment', + filename: (@commit.id.to_s + ".patch") ) end end diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index a054940738e..7696e97a7b2 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -2,16 +2,14 @@ class DashboardController < ApplicationController respond_to :html def index - @projects = current_user.projects.includes(:events).order("events.created_at DESC") - @projects = @projects.page(params[:page]).per(40) - - @events = Event.where(:project_id => current_user.projects.map(&:id)).recent.limit(20) - + @projects = current_user.projects_with_events.page(params[:page]).per(40) + @events = Event.recent_for_user(current_user).limit(20).offset(params[:offset] || 0) @last_push = current_user.recent_push respond_to do |format| format.html - format.atom { render :layout => false } + format.js + format.atom { render layout: false } end end @@ -30,7 +28,7 @@ class DashboardController < ApplicationController respond_to do |format| format.html - format.atom { render :layout => false } + format.atom { render layout: false } end end end diff --git a/app/controllers/deploy_keys_controller.rb b/app/controllers/deploy_keys_controller.rb index 9d4e0483d65..82c10512a64 100644 --- a/app/controllers/deploy_keys_controller.rb +++ b/app/controllers/deploy_keys_controller.rb @@ -40,7 +40,7 @@ class DeployKeysController < ApplicationController respond_to do |format| format.html { redirect_to project_deploy_keys_url } - format.js { render :nothing => true } + format.js { render nothing: true } end end end diff --git a/app/controllers/hooks_controller.rb b/app/controllers/hooks_controller.rb index 9627aba9771..c81e6b05cb3 100644 --- a/app/controllers/hooks_controller.rb +++ b/app/controllers/hooks_controller.rb @@ -6,38 +6,35 @@ class HooksController < ApplicationController # Authorize before_filter :add_project_abilities before_filter :authorize_read_project! - before_filter :authorize_admin_project!, :only => [:new, :create, :destroy] + before_filter :authorize_admin_project!, only: [:new, :create, :destroy] respond_to :html def index - @hooks = @project.web_hooks.all - @hook = WebHook.new + @hooks = @project.hooks.all + @hook = ProjectHook.new end def create - @hook = @project.web_hooks.new(params[:hook]) + @hook = @project.hooks.new(params[:hook]) @hook.save if @hook.valid? redirect_to project_hooks_path(@project) else - @hooks = @project.web_hooks.all + @hooks = @project.hooks.all render :index end end def test - @hook = @project.web_hooks.find(params[:id]) - commits = @project.commits(@project.default_branch, nil, 3) - data = @project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{@project.default_branch}", current_user) - @hook.execute(data) + TestHookContext.new(project, current_user, params).execute redirect_to :back end def destroy - @hook = @project.web_hooks.find(params[:id]) + @hook = @project.hooks.find(params[:id]) @hook.destroy redirect_to project_hooks_path(@project) diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index c36258c818a..889a7d98033 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -2,7 +2,7 @@ class IssuesController < ApplicationController before_filter :authenticate_user! before_filter :project before_filter :module_enabled - before_filter :issue, :only => [:edit, :update, :destroy, :show] + before_filter :issue, only: [:edit, :update, :destroy, :show] helper_method :issues_filter layout "project" @@ -14,13 +14,13 @@ class IssuesController < ApplicationController before_filter :authorize_read_issue! # Allow write(create) issue - before_filter :authorize_write_issue!, :only => [:new, :create] + before_filter :authorize_write_issue!, only: [:new, :create] # Allow modify issue - before_filter :authorize_modify_issue!, :only => [:close, :edit, :update] + before_filter :authorize_modify_issue!, only: [:close, :edit, :update] # Allow destroy issue - before_filter :authorize_admin_issue!, :only => [:destroy] + before_filter :authorize_admin_issue!, only: [:destroy] respond_to :js, :html @@ -32,7 +32,7 @@ class IssuesController < ApplicationController respond_to do |format| format.html # index.html.erb format.js - format.atom { render :layout => false } + format.atom { render layout: false } end end @@ -46,7 +46,7 @@ class IssuesController < ApplicationController end def show - @note = @project.notes.new(:noteable => @issue) + @note = @project.notes.new(noteable: @issue) respond_to do |format| format.html @@ -66,7 +66,7 @@ class IssuesController < ApplicationController end def update - @issue.update_attributes(params[:issue].merge(:author_id_of_changes => current_user.id)) + @issue.update_attributes(params[:issue].merge(author_id_of_changes: current_user.id)) respond_to do |format| format.js @@ -87,20 +87,20 @@ class IssuesController < ApplicationController respond_to do |format| format.html { redirect_to project_issues_path } - format.js { render :nothing => true } + format.js { render nothing: true } end end def sort return render_404 unless can?(current_user, :admin_issue, @project) - @issues = @project.issues.where(:id => params['issue']) + @issues = @project.issues.where(id: params['issue']) @issues.each do |issue| issue.position = params['issue'].index(issue.id.to_s) + 1 issue.save end - render :nothing => true + render nothing: true end def search @@ -110,7 +110,12 @@ class IssuesController < ApplicationController @issues = @issues.where("title LIKE ?", "%#{terms}%") unless terms.blank? @issues = @issues.page(params[:page]).per(100) - render :partial => 'issues' + render partial: 'issues' + end + + def bulk_update + result = IssuesBulkUpdateContext.new(project, current_user, params).execute + redirect_to :back, notice: "#{result[:count]} issues updated" end protected @@ -139,10 +144,19 @@ class IssuesController < ApplicationController else @project.issues.opened end - @issues = @issues.where(:assignee_id => params[:assignee_id]) if params[:assignee_id].present? - @issues = @issues.where(:milestone_id => params[:milestone_id]) if params[:milestone_id].present? @issues = @issues.tagged_with(params[:label_name]) if params[:label_name].present? @issues = @issues.includes(:author, :project).order("updated_at") + + # Filter by specific assignee_id (or lack thereof)? + if params[:assignee_id].present? + @issues = @issues.where(assignee_id: (params[:assignee_id] == '0' ? nil : params[:assignee_id])) + end + + # Filter by specific milestone_id (or lack thereof)? + if params[:milestone_id].present? + @issues = @issues.where(milestone_id: (params[:milestone_id] == '0' ? nil : params[:milestone_id])) + end + @issues end diff --git a/app/controllers/keys_controller.rb b/app/controllers/keys_controller.rb index ce49e3e72c6..1a25d834e12 100644 --- a/app/controllers/keys_controller.rb +++ b/app/controllers/keys_controller.rb @@ -29,7 +29,7 @@ class KeysController < ApplicationController respond_to do |format| format.html { redirect_to keys_url } - format.js { render :nothing => true } + format.js { render nothing: true } end end end diff --git a/app/controllers/labels_controller.rb b/app/controllers/labels_controller.rb new file mode 100644 index 00000000000..e703f822982 --- /dev/null +++ b/app/controllers/labels_controller.rb @@ -0,0 +1,25 @@ +class LabelsController < ApplicationController + before_filter :authenticate_user! + before_filter :project + before_filter :module_enabled + + layout "project" + + # Authorize + before_filter :add_project_abilities + + # Allow read any issue + before_filter :authorize_read_issue! + + respond_to :js, :html + + def index + @labels = @project.issues.tag_counts_on(:labels).order('count DESC') + end + + protected + + def module_enabled + return render_404 unless @project.issues_enabled + end +end diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index ec4ed45fedf..187bb407b2d 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -2,9 +2,9 @@ class MergeRequestsController < ApplicationController before_filter :authenticate_user! before_filter :project before_filter :module_enabled - before_filter :merge_request, :only => [:edit, :update, :destroy, :show, :commits, :diffs, :automerge, :automerge_check, :raw] - before_filter :validates_merge_request, :only => [:show, :diffs, :raw] - before_filter :define_show_vars, :only => [:show, :diffs] + before_filter :merge_request, only: [:edit, :update, :destroy, :show, :commits, :diffs, :automerge, :automerge_check, :raw] + before_filter :validates_merge_request, only: [:show, :diffs, :raw] + before_filter :define_show_vars, only: [:show, :diffs] layout "project" # Authorize @@ -14,26 +14,17 @@ class MergeRequestsController < ApplicationController before_filter :authorize_read_merge_request! # Allow write(create) merge_request - before_filter :authorize_write_merge_request!, :only => [:new, :create] + before_filter :authorize_write_merge_request!, only: [:new, :create] # Allow modify merge_request - before_filter :authorize_modify_merge_request!, :only => [:close, :edit, :update, :sort] + before_filter :authorize_modify_merge_request!, only: [:close, :edit, :update, :sort] # Allow destroy merge_request - before_filter :authorize_admin_merge_request!, :only => [:destroy] + before_filter :authorize_admin_merge_request!, only: [:destroy] def index - @merge_requests = @project.merge_requests - - @merge_requests = case params[:f].to_i - when 1 then @merge_requests - when 2 then @merge_requests.closed - when 3 then @merge_requests.opened.assigned(current_user) - else @merge_requests.opened - end.page(params[:page]).per(20) - - @merge_requests = @merge_requests.includes(:author, :project).order("closed, created_at desc") + @merge_requests = MergeRequestsLoad.new(project, current_user, params).execute end def show @@ -75,7 +66,7 @@ class MergeRequestsController < ApplicationController end def update - if @merge_request.update_attributes(params[:merge_request].merge(:author_id_of_changes => current_user.id)) + if @merge_request.update_attributes(params[:merge_request].merge(author_id_of_changes: current_user.id)) @merge_request.reload_code @merge_request.mark_as_unchecked redirect_to [@project, @merge_request], notice: 'Merge request was successfully updated.' @@ -88,7 +79,7 @@ class MergeRequestsController < ApplicationController if @merge_request.unchecked? @merge_request.check_if_can_be_merged end - render :json => {:state => @merge_request.human_state} + render json: {state: @merge_request.human_state} end def automerge @@ -112,10 +103,12 @@ class MergeRequestsController < ApplicationController def branch_from @commit = project.commit(params[:ref]) + @commit = CommitDecorator.decorate(@commit) end def branch_to @commit = project.commit(params[:ref]) + @commit = CommitDecorator.decorate(@commit) end protected @@ -147,10 +140,11 @@ class MergeRequestsController < ApplicationController def define_show_vars # Build a note object for comment form - @note = @project.notes.new(:noteable => @merge_request) + @note = @project.notes.new(noteable: @merge_request) # Get commits from repository # or from cache if already merged @commits = @merge_request.commits + @commits = CommitDecorator.decorate(@commits) end end diff --git a/app/controllers/milestones_controller.rb b/app/controllers/milestones_controller.rb index 1f2490cb6ef..7acb3781fbb 100644 --- a/app/controllers/milestones_controller.rb +++ b/app/controllers/milestones_controller.rb @@ -2,7 +2,7 @@ class MilestonesController < ApplicationController before_filter :authenticate_user! before_filter :project before_filter :module_enabled - before_filter :milestone, :only => [:edit, :update, :destroy, :show] + before_filter :milestone, only: [:edit, :update, :destroy, :show] layout "project" # Authorize @@ -12,7 +12,7 @@ class MilestonesController < ApplicationController before_filter :authorize_read_milestone! # Allow admin milestone - before_filter :authorize_admin_milestone!, :except => [:index, :show] + before_filter :authorize_admin_milestone!, except: [:index, :show] respond_to :html @@ -77,7 +77,7 @@ class MilestonesController < ApplicationController respond_to do |format| format.html { redirect_to project_milestones_path } - format.js { render :nothing => true } + format.js { render nothing: true } end end diff --git a/app/controllers/notes_controller.rb b/app/controllers/notes_controller.rb index a2638d9597c..f003ea7bf66 100644 --- a/app/controllers/notes_controller.rb +++ b/app/controllers/notes_controller.rb @@ -5,7 +5,7 @@ class NotesController < ApplicationController before_filter :add_project_abilities before_filter :authorize_read_note! - before_filter :authorize_write_note!, :only => [:create] + before_filter :authorize_write_note!, only: [:create] respond_to :js @@ -15,11 +15,7 @@ class NotesController < ApplicationController end def create - @note = @project.notes.new(params[:note]) - @note.author = current_user - @note.notify = true if params[:notify] == '1' - @note.notify_author = true if params[:notify_author] == '1' - @note.save + @note = Notes::CreateContext.new(project, current_user, params).execute respond_to do |format| format.html {redirect_to :back} @@ -33,32 +29,17 @@ class NotesController < ApplicationController @note.destroy respond_to do |format| - format.js { render :nothing => true } + format.js { render nothing: true } end end - protected + def preview + render text: view_context.markdown(params[:note]) + end - def notes - @notes = case params[:target_type] - when "commit" - then project.commit_notes(project.commit((params[:target_id]))).fresh.limit(20) - when "snippet" - then project.snippets.find(params[:target_id]).notes - when "wall" - then project.common_notes.order("created_at DESC").fresh.limit(50) - when "issue" - then project.issues.find(params[:target_id]).notes.inc_author.order("created_at DESC").limit(20) - when "merge_request" - then project.merge_requests.find(params[:target_id]).notes.inc_author.order("created_at DESC").limit(20) - end + protected - @notes = if params[:last_id] - @notes.where("id > ?", params[:last_id]) - elsif params[:first_id] - @notes.where("id < ?", params[:first_id]) - else - @notes - end + def notes + @notes = Notes::LoadContext.new(project, current_user, params).execute end end diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index fb759c371c4..d472936b4b4 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -3,20 +3,16 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController # Extend the standard message generation to accept our custom exception def failure_message exception = env["omniauth.error"] - if exception.class == OmniAuth::Error - error = exception.message - else - error = exception.error_reason if exception.respond_to?(:error_reason) - error ||= exception.error if exception.respond_to?(:error) - error ||= env["omniauth.error.type"].to_s - end + error = exception.error_reason if exception.respond_to?(:error_reason) + error ||= exception.error if exception.respond_to?(:error) + error ||= exception.message if exception.respond_to?(:message) + error ||= env["omniauth.error.type"].to_s error.to_s.humanize if error end def ldap # We only find ourselves here if the authentication to LDAP was successful. - info = request.env["omniauth.auth"]["info"] - @user = User.find_for_ldap_auth(info) + @user = User.find_for_ldap_auth(request.env["omniauth.auth"], current_user) if @user.persisted? @user.remember_me = true end diff --git a/app/controllers/profile_controller.rb b/app/controllers/profile_controller.rb index 0da463757f3..a95a331096a 100644 --- a/app/controllers/profile_controller.rb +++ b/app/controllers/profile_controller.rb @@ -1,36 +1,32 @@ class ProfileController < ApplicationController layout "profile" + before_filter :user + def show - @user = current_user end def design - @user = current_user end def update - @user = current_user @user.update_attributes(params[:user]) redirect_to :back end def token - @user = current_user end def password - @user = current_user end def password_update params[:user].reject!{ |k, v| k != "password" && k != "password_confirmation"} - @user = current_user if @user.update_attributes(params[:user]) flash[:notice] = "Password was successfully updated. Please login with it" redirect_to new_user_session_path else - render :action => "password" + render action: "password" end end @@ -38,4 +34,10 @@ class ProfileController < ApplicationController current_user.reset_authentication_token! redirect_to profile_token_path end + + private + + def user + @user = current_user + end end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 26b62cba9f9..bd7f811e59f 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -1,14 +1,14 @@ -require File.join(Rails.root, 'lib', 'graph_commit') +require Rails.root.join('lib', 'gitlab', 'graph_commit') class ProjectsController < ApplicationController - before_filter :project, :except => [:index, :new, :create] + before_filter :project, except: [:index, :new, :create] layout :determine_layout # Authorize before_filter :add_project_abilities - before_filter :authorize_read_project!, :except => [:index, :new, :create] - before_filter :authorize_admin_project!, :only => [:edit, :update, :destroy] - before_filter :require_non_empty_project, :only => [:blob, :tree, :graph] + before_filter :authorize_read_project!, except: [:index, :new, :create] + before_filter :authorize_admin_project!, only: [:edit, :update, :destroy] + before_filter :require_non_empty_project, only: [:blob, :tree, :graph] def new @project = Project.new @@ -35,7 +35,7 @@ class ProjectsController < ApplicationController def update respond_to do |format| if project.update_attributes(params[:project]) - format.html { redirect_to edit_project_path(project), :notice => 'Project was successfully updated.' } + format.html { redirect_to edit_project_path(project), notice: 'Project was successfully updated.' } format.js else format.html { render action: "edit" } @@ -78,7 +78,7 @@ class ProjectsController < ApplicationController end def graph - @days_json, @commits_json = GraphCommit.to_graph(project) + @days_json, @commits_json = Gitlab::GraphCommit.to_graph(project) end def destroy diff --git a/app/controllers/protected_branches_controller.rb b/app/controllers/protected_branches_controller.rb index 0b86f5253ce..78c9c9effa6 100644 --- a/app/controllers/protected_branches_controller.rb +++ b/app/controllers/protected_branches_controller.rb @@ -6,7 +6,7 @@ class ProtectedBranchesController < ApplicationController before_filter :authorize_read_project! before_filter :require_non_empty_project - before_filter :authorize_admin_project!, :only => [:destroy, :create] + before_filter :authorize_admin_project!, only: [:destroy, :create] before_filter :render_full_content layout "project" @@ -26,7 +26,7 @@ class ProtectedBranchesController < ApplicationController respond_to do |format| format.html { redirect_to project_protected_branches_path } - format.js { render :nothing => true } + format.js { render nothing: true } end end end diff --git a/app/controllers/refs_controller.rb b/app/controllers/refs_controller.rb index b610c9f34d4..3f81a2ca1a3 100644 --- a/app/controllers/refs_controller.rb +++ b/app/controllers/refs_controller.rb @@ -9,7 +9,7 @@ class RefsController < ApplicationController before_filter :require_non_empty_project before_filter :ref - before_filter :define_tree_vars, :only => [:tree, :blob, :blame, :logs_tree] + before_filter :define_tree_vars, only: [:tree, :blob, :blame, :logs_tree] before_filter :render_full_content layout "project" @@ -20,7 +20,7 @@ class RefsController < ApplicationController new_path = if params[:destination] == "tree" tree_project_ref_path(@project, params[:ref]) else - project_commits_path(@project, :ref => params[:ref]) + project_commits_path(@project, ref: params[:ref]) end redirect_to new_path @@ -51,9 +51,10 @@ class RefsController < ApplicationController @logs = contents.map do |content| file = params[:path] ? File.join(params[:path], content.name) : content.name last_commit = @project.commits(@commit.id, file, 1).last - { - :file_name => content.name, - :commit => last_commit + last_commit = CommitDecorator.decorate(last_commit) + { + file_name: content.name, + commit: last_commit } end end @@ -69,9 +70,9 @@ class RefsController < ApplicationController send_data( @tree.data, - :type => mime_type, - :disposition => 'inline', - :filename => @tree.name + type: mime_type, + disposition: 'inline', + filename: @tree.name ) else head(404) @@ -89,6 +90,7 @@ class RefsController < ApplicationController @repo = project.repo @commit = project.commit(@ref) + @commit = CommitDecorator.decorate(@commit) @tree = Tree.new(@commit.tree, project, @ref, params[:path]) @tree = TreeDecorator.new(@tree) @hex_path = Digest::SHA1.hexdigest(params[:path] || "/") diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index dfc318c5fb1..71e2d92b2b2 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -1,14 +1,15 @@ class SearchController < ApplicationController def show query = params[:search] - if query.blank? - @projects = [] - @merge_requests = [] - @issues = [] - else + + @projects = [] + @merge_requests = [] + @issues = [] + + if query.present? @projects = current_user.projects.search(query).limit(10) - @merge_requests = MergeRequest.where(:project_id => current_user.project_ids).search(query).limit(10) - @issues = Issue.where(:project_id => current_user.project_ids).search(query).limit(10) + @merge_requests = MergeRequest.where(project_id: current_user.project_ids).search(query).limit(10) + @issues = Issue.where(project_id: current_user.project_ids).search(query).limit(10) end end end diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb index 3d56bebe2fe..f852e425891 100644 --- a/app/controllers/snippets_controller.rb +++ b/app/controllers/snippets_controller.rb @@ -1,7 +1,7 @@ class SnippetsController < ApplicationController before_filter :authenticate_user! before_filter :project - before_filter :snippet, :only => [:show, :edit, :destroy, :update, :raw] + before_filter :snippet, only: [:show, :edit, :destroy, :update, :raw] layout "project" # Authorize @@ -11,13 +11,13 @@ class SnippetsController < ApplicationController before_filter :authorize_read_snippet! # Allow write(create) snippet - before_filter :authorize_write_snippet!, :only => [:new, :create] + before_filter :authorize_write_snippet!, only: [:new, :create] # Allow modify snippet - before_filter :authorize_modify_snippet!, :only => [:edit, :update] + before_filter :authorize_modify_snippet!, only: [:edit, :update] # Allow destroy snippet - before_filter :authorize_admin_snippet!, :only => [:destroy] + before_filter :authorize_admin_snippet!, only: [:destroy] respond_to :html @@ -55,7 +55,7 @@ class SnippetsController < ApplicationController end def show - @note = @project.notes.new(:noteable => @snippet) + @note = @project.notes.new(noteable: @snippet) render_full_content end @@ -70,9 +70,9 @@ class SnippetsController < ApplicationController def raw send_data( @snippet.content, - :type => "text/plain", - :disposition => 'inline', - :filename => @snippet.file_name + type: "text/plain", + disposition: 'inline', + filename: @snippet.file_name ) end diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb index ab51c19e0c8..0846f096554 100644 --- a/app/controllers/team_members_controller.rb +++ b/app/controllers/team_members_controller.rb @@ -5,10 +5,11 @@ class TeamMembersController < ApplicationController # Authorize before_filter :add_project_abilities before_filter :authorize_read_project! - before_filter :authorize_admin_project!, :except => [:show] + before_filter :authorize_admin_project!, except: [:show] def show @team_member = project.users_projects.find(params[:id]) + @events = @team_member.user.recent_events.where(:project_id => @project.id).limit(7) end def new @@ -41,7 +42,7 @@ class TeamMembersController < ApplicationController respond_to do |format| format.html { redirect_to team_project_path(@project) } - format.js { render :nothing => true } + format.js { render nothing: true } end end end diff --git a/app/controllers/wikis_controller.rb b/app/controllers/wikis_controller.rb index 9bcd20c3187..55ccfe72116 100644 --- a/app/controllers/wikis_controller.rb +++ b/app/controllers/wikis_controller.rb @@ -2,33 +2,37 @@ class WikisController < ApplicationController before_filter :project before_filter :add_project_abilities before_filter :authorize_read_wiki! - before_filter :authorize_write_wiki!, :only => [:edit, :create, :history] - before_filter :authorize_admin_wiki!, :only => :destroy + before_filter :authorize_write_wiki!, only: [:edit, :create, :history] + before_filter :authorize_admin_wiki!, only: :destroy layout "project" + def pages + @wikis = @project.wikis.group(:slug).order("created_at") + end + def show if params[:old_page_id] @wiki = @project.wikis.find(params[:old_page_id]) else - @wiki = @project.wikis.where(:slug => params[:id]).order("created_at").last + @wiki = @project.wikis.where(slug: params[:id]).order("created_at").last end - unless @wiki - return render_404 unless can?(current_user, :write_wiki, @project) - end + @note = @project.notes.new(noteable: @wiki) - respond_to do |format| - if @wiki - format.html + if @wiki + render 'show' + else + if can?(current_user, :write_wiki, @project) + @wiki = @project.wikis.new(slug: params[:id]) + render 'edit' else - @wiki = @project.wikis.new(:slug => params[:id]) - format.html { render "edit" } + render 'empty' end end end def edit - @wiki = @project.wikis.where(:slug => params[:id]).order("created_at").last + @wiki = @project.wikis.where(slug: params[:id]).order("created_at").last @wiki = Wiki.regenerate_from @wiki end @@ -46,11 +50,11 @@ class WikisController < ApplicationController end def history - @wikis = @project.wikis.where(:slug => params[:id]).order("created_at") + @wikis = @project.wikis.where(slug: params[:id]).order("created_at") end def destroy - @wikis = @project.wikis.where(:slug => params[:id]).delete_all + @wikis = @project.wikis.where(slug: params[:id]).delete_all respond_to do |format| format.html { redirect_to project_wiki_path(@project, :index), notice: "Page was successfully deleted" } diff --git a/app/decorators/application_decorator.rb b/app/decorators/application_decorator.rb index 8c35cae98fd..3023699e700 100644 --- a/app/decorators/application_decorator.rb +++ b/app/decorators/application_decorator.rb @@ -1,4 +1,4 @@ -class ApplicationDecorator < Drapper::Base +class ApplicationDecorator < Draper::Base # Lazy Helpers # PRO: Call Rails helpers without the h. proxy # ex: number_to_currency(model.price) @@ -15,7 +15,7 @@ class ApplicationDecorator < Drapper::Base # # def formatted_timestamp(time) # h.content_tag :span, time.strftime("%a %m/%d/%y"), - # :class => 'timestamp' + # class: 'timestamp' # end # # def created_at diff --git a/app/decorators/event_decorator.rb b/app/decorators/event_decorator.rb index 50aaa615d49..7df9081f045 100644 --- a/app/decorators/event_decorator.rb +++ b/app/decorators/event_decorator.rb @@ -19,7 +19,7 @@ class EventDecorator < ApplicationDecorator elsif self.merge_request? h.project_merge_request_url(self.project, self.merge_request) elsif self.push? - h.project_commits_url(self.project, :ref => self.ref_name) + h.project_commits_url(self.project, ref: self.ref_name) end end end diff --git a/app/decorators/tree_decorator.rb b/app/decorators/tree_decorator.rb index 2b82a42561b..80c48da75bf 100644 --- a/app/decorators/tree_decorator.rb +++ b/app/decorators/tree_decorator.rb @@ -8,14 +8,14 @@ class TreeDecorator < ApplicationDecorator #parts = parts[0...-1] if is_blob? - yield(h.link_to("..", "#", :remote => :true)) if parts.count > max_links + yield(h.link_to("..", "#", remote: :true)) if parts.count > max_links parts.each do |part| part_path = File.join(part_path, part) unless part_path.empty? part_path = part if part_path.empty? next unless parts.last(2).include?(part) if parts.count > max_links - yield(h.link_to(h.truncate(part, :length => 40), h.tree_file_project_ref_path(project, ref, :path => part_path), :remote => :true)) + yield(h.link_to(h.truncate(part, length: 40), h.tree_file_project_ref_path(project, ref, path: part_path), remote: :true)) end end end @@ -30,7 +30,7 @@ class TreeDecorator < ApplicationDecorator end def history_path - h.project_commits_path(project, :path => path, :ref => ref) + h.project_commits_path(project, path: path, ref: ref) end def mb_size diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 3f15fd9237f..38191f55571 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -2,10 +2,13 @@ require 'digest/md5' module ApplicationHelper def gravatar_icon(user_email = '', size = 40) - return unless user_email - gravatar_host = request.ssl? ? "https://secure.gravatar.com" : "http://www.gravatar.com" - user_email.strip! - "#{gravatar_host}/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=identicon" + if Gitlab.config.disable_gravatar? || user_email.blank? + 'no_avatar.png' + else + gravatar_prefix = request.ssl? ? "https://secure" : "http://www" + user_email.strip! + "#{gravatar_prefix}.gravatar.com/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=identicon" + end end def request_protocol @@ -42,39 +45,24 @@ module ApplicationHelper grouped_options_for_select(options, @ref || @project.default_branch) end - def markdown(text) - @__renderer ||= Redcarpet::Markdown.new(Redcarpet::Render::GitlabHTML.new(filter_html: true), { - no_intra_emphasis: true, - tables: true, - fenced_code_blocks: true, - autolink: true, - strikethrough: true, - lax_html_blocks: true, - space_after_headers: true, - superscript: true - }) - - @__renderer.render(text).html_safe - end - def search_autocomplete_source - projects = current_user.projects.map{ |p| { :label => p.name, :url => project_path(p) } } + projects = current_user.projects.map{ |p| { label: p.name, url: project_path(p) } } default_nav = [ - { :label => "Profile", :url => profile_path }, - { :label => "Keys", :url => keys_path }, - { :label => "Dashboard", :url => root_path }, - { :label => "Admin", :url => admin_root_path } + { label: "Profile", url: profile_path }, + { label: "Keys", url: keys_path }, + { label: "Dashboard", url: root_path }, + { label: "Admin", url: admin_root_path } ] project_nav = [] if @project && !@project.new_record? project_nav = [ - { :label => "#{@project.name} / Issues", :url => project_issues_path(@project) }, - { :label => "#{@project.name} / Wall", :url => wall_project_path(@project) }, - { :label => "#{@project.name} / Tree", :url => tree_project_ref_path(@project, @project.root_ref) }, - { :label => "#{@project.name} / Commits", :url => project_commits_path(@project) }, - { :label => "#{@project.name} / Team", :url => team_project_path(@project) } + { label: "#{@project.name} / Issues", url: project_issues_path(@project) }, + { label: "#{@project.name} / Wall", url: wall_project_path(@project) }, + { label: "#{@project.name} / Tree", url: tree_project_ref_path(@project, @project.root_ref) }, + { label: "#{@project.name} / Commits", url: project_commits_path(@project) }, + { label: "#{@project.name} / Team", url: team_project_path(@project) } ] end @@ -104,7 +92,7 @@ module ApplicationHelper when :wall; wall_tab? when :wiki; controller.controller_name == "wikis" when :issues; issues_tab? - when :network; current_page?(:controller => "projects", :action => "graph", :id => @project) + when :network; current_page?(controller: "projects", action: "graph", id: @project) when :merge_requests; controller.controller_name == "merge_requests" # Dashboard Area @@ -115,17 +103,17 @@ module ApplicationHelper when :root; current_page?(dashboard_path) || current_page?(root_path) # Profile Area - when :profile; current_page?(:controller => "profile", :action => :show) - when :password; current_page?(:controller => "profile", :action => :password) - when :token; current_page?(:controller => "profile", :action => :token) - when :design; current_page?(:controller => "profile", :action => :design) + when :profile; current_page?(controller: "profile", action: :show) + when :password; current_page?(controller: "profile", action: :password) + when :token; current_page?(controller: "profile", action: :token) + when :design; current_page?(controller: "profile", action: :design) when :ssh_keys; controller.controller_name == "keys" # Admin Area when :admin_root; controller.controller_name == "dashboard" when :admin_users; controller.controller_name == 'users' when :admin_projects; controller.controller_name == "projects" - when :admin_emails; controller.controller_name == 'mailer' + when :admin_hooks; controller.controller_name == 'hooks' when :admin_resque; controller.controller_name == 'resque' when :admin_logs; controller.controller_name == 'logs' diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index fa87632d176..16ecfb1f89b 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -1,22 +1,4 @@ module CommitsHelper - def commit_msg_with_link_to_issues(project, message) - return '' unless message - out = '' - message.split(/(#[0-9]+)/m).each do |m| - if m =~ /(#([0-9]+))/m - begin - issue = project.issues.find($2) - out += link_to($1, project_issue_path(project, $2)) - rescue - out += $1 - end - else - out += m - end - end - preserve out - end - def identification_type(line) if line[0] == "+" "new" diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb new file mode 100644 index 00000000000..88e3473baf2 --- /dev/null +++ b/app/helpers/gitlab_markdown_helper.rb @@ -0,0 +1,70 @@ +module GitlabMarkdownHelper + # Replaces references (i.e. @abc, #123, !456, ...) in the text with links to + # the appropriate items in Gitlab. + # + # text - the source text + # html_options - extra options for the reference links as given to link_to + # + # note: reference links will only be generated if @project is set + # + # see Gitlab::Markdown for details on the supported syntax + def gfm(text, html_options = {}) + return text if text.nil? + return text if @project.nil? + + # Extract pre blocks so they are not altered + # from http://github.github.com/github-flavored-markdown/ + extractions = {} + text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) do |match| + md5 = Digest::MD5.hexdigest(match) + extractions[md5] = match + "{gfm-extraction-#{md5}}" + end + + # TODO: add popups with additional information + + parser = Gitlab::Markdown.new(@project, html_options) + text = parser.parse(text) + + # Insert pre block extractions + text.gsub!(/\{gfm-extraction-(\h{32})\}/) do + extractions[$1] + end + + text.html_safe + end + + # Use this in places where you would normally use link_to(gfm(...), ...). + # + # It solves a problem occurring with nested links (i.e. + # "<a>outer text <a>gfm ref</a> more outer text</a>"). This will not be + # interpreted as intended. Browsers will parse something like + # "<a>outer text </a><a>gfm ref</a> more outer text" (notice the last part is + # not linked any more). link_to_gfm corrects that. It wraps all parts to + # explicitly produce the correct linking behavior (i.e. + # "<a>outer text </a><a>gfm ref</a><a> more outer text</a>"). + def link_to_gfm(body, url, html_options = {}) + gfm_body = gfm(body, html_options) + + gfm_body.gsub!(%r{<a.*?>.*?</a>}m) do |match| + "</a>#{match}#{link_to("", url, html_options)[0..-5]}" # "</a>".length +1 + end + + link_to(gfm_body.html_safe, url, html_options) + end + + def markdown(text) + @__renderer ||= Redcarpet::Markdown.new(Redcarpet::Render::GitlabHTML.new(self, filter_html: true, with_toc_data: true), { + no_intra_emphasis: true, + tables: true, + fenced_code_blocks: true, + autolink: true, + strikethrough: true, + lax_html_blocks: true, + space_after_headers: true, + superscript: true + }) + + @__renderer.render(text).html_safe + end +end diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 0982aaccc2e..d4d6c2d4205 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -9,7 +9,7 @@ module IssuesHelper tm = project.team_member_by_id(issue.assignee_id) if tm - link_to issue.assignee_name, project_team_member_path(project, tm), :class => "author_link" + link_to issue.assignee_name, project_team_member_path(project, tm), class: "author_link" else issue.assignee_name end @@ -20,7 +20,7 @@ module IssuesHelper tm = project.team_member_by_id(issue.author_id) if tm - link_to issue.author_name, project_team_member_path(project, tm), :class => "author_link" + link_to issue.author_name, project_team_member_path(project, tm), class: "author_link" else issue.author_name end @@ -36,4 +36,11 @@ module IssuesHelper def issue_tags @project.issues.tag_counts_on(:labels).map(&:name) end + + # Returns an OpenStruct object suitable for use by <tt>options_from_collection_for_select</tt> + # to allow filtering issues by an unassigned User or Milestone + def unassigned_filter + # Milestone uses :title, Issue uses :name + OpenStruct.new(id: 0, title: 'Unspecified', name: 'Unassigned') + end end diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index f9bfc8cdcf6..62ac5e55d43 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -4,7 +4,7 @@ module MergeRequestsHelper tm = project.team_member_by_id(merge_request.assignee_id) if tm - link_to merge_request.assignee_name, project_team_member_path(project, tm), :class => "author_link" + link_to merge_request.assignee_name, project_team_member_path(project, tm), class: "author_link" else merge_request.assignee_name end @@ -15,7 +15,7 @@ module MergeRequestsHelper tm = project.team_member_by_id(merge_request.author_id) if tm - link_to merge_request.author_name, project_team_member_path(project, tm), :class => "author_link" + link_to merge_request.author_name, project_team_member_path(project, tm), class: "author_link" else merge_request.author_name end @@ -24,10 +24,10 @@ module MergeRequestsHelper def new_mr_path_from_push_event(event) new_project_merge_request_path( event.project, - :merge_request => { - :source_branch => event.branch_name, - :target_branch => event.project.root_ref, - :title => event.branch_name.titleize + merge_request: { + source_branch: event.branch_name, + target_branch: event.project.root_ref, + title: event.branch_name.titleize } ) end diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb index fa5ca166d6b..1740864bbb2 100644 --- a/app/helpers/tab_helper.rb +++ b/app/helpers/tab_helper.rb @@ -4,12 +4,12 @@ module TabHelper end def wall_tab? - current_page?(:controller => "projects", :action => "wall", :id => @project) + current_page?(controller: "projects", action: "wall", id: @project) end def project_tab_class [:show, :files, :team, :edit, :update].each do |action| - return "current" if current_page?(:controller => "projects", :action => action, :id => @project) + return "current" if current_page?(controller: "projects", action: action, id: @project) end if ['snippets', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index c673eb3d161..d0571b7b2c2 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -1,6 +1,7 @@ class Notify < ActionMailer::Base include Resque::Mailer add_template_helper ApplicationHelper + add_template_helper GitlabMarkdownHelper default_url_options[:host] = Gitlab.config.web_host default_url_options[:protocol] = Gitlab.config.web_protocol @@ -11,57 +12,102 @@ class Notify < ActionMailer::Base def new_user_email(user_id, password) @user = User.find(user_id) @password = password - mail(:to => @user.email, :subject => "gitlab | Account was created for you") + mail(to: @user.email, subject: subject("Account was created for you")) end def new_issue_email(issue_id) @issue = Issue.find(issue_id) - mail(:to => @issue.assignee_email, :subject => "gitlab | New Issue was created") + @project = @issue.project + mail(to: @issue.assignee_email, subject: subject("new issue ##{@issue.id}", @issue.title)) end def note_wall_email(recipient_id, note_id) - recipient = User.find(recipient_id) @note = Note.find(note_id) - mail(:to => recipient.email, :subject => "gitlab | #{@note.project_name} ") + @project = @note.project + mail(to: recipient(recipient_id), subject: subject) end def note_commit_email(recipient_id, note_id) - recipient = User.find(recipient_id) @note = Note.find(note_id) @commit = @note.target - mail(:to => recipient.email, :subject => "gitlab | note for commit | #{@note.project_name} ") + @commit = CommitDecorator.decorate(@commit) + @project = @note.project + mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title)) end def note_merge_request_email(recipient_id, note_id) - recipient = User.find(recipient_id) @note = Note.find(note_id) @merge_request = @note.noteable - mail(:to => recipient.email, :subject => "gitlab | note for merge request | #{@note.project_name} ") + @project = @note.project + mail(to: recipient(recipient_id), subject: subject("note for merge request !#{@merge_request.id}")) end def note_issue_email(recipient_id, note_id) - recipient = User.find(recipient_id) @note = Note.find(note_id) @issue = @note.noteable - mail(:to => recipient.email, :subject => "gitlab | note for issue #{@issue.id} | #{@note.project_name} ") + @project = @note.project + mail(to: recipient(recipient_id), subject: subject("note for issue ##{@issue.id}")) + end + + def note_wiki_email(recipient_id, note_id) + @note = Note.find(note_id) + @wiki = @note.noteable + @project = @note.project + mail(to: recipient(recipient_id), subject: subject("note for wiki")) end def new_merge_request_email(merge_request_id) @merge_request = MergeRequest.find(merge_request_id) - mail(:to => @merge_request.assignee_email, :subject => "gitlab | new merge request | #{@merge_request.title} ") + @project = @merge_request.project + mail(to: @merge_request.assignee_email, subject: subject("new merge request !#{@merge_request.id}", @merge_request.title)) end def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id) - recipient = User.find(recipient_id) @merge_request = MergeRequest.find(merge_request_id) @previous_assignee ||= User.find(previous_assignee_id) - mail(:to => recipient.email, :subject => "gitlab | merge request changed | #{@merge_request.title} ") + @project = @merge_request.project + mail(to: recipient(recipient_id), subject: subject("changed merge request !#{@merge_request.id}", @merge_request.title)) end def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id) - recipient = User.find(recipient_id) @issue = Issue.find(issue_id) @previous_assignee ||= User.find(previous_assignee_id) - mail(:to => recipient.email, :subject => "gitlab | changed issue | #{@issue.title} ") + @project = @issue.project + mail(to: recipient(recipient_id), subject: subject("changed issue ##{@issue.id}", @issue.title)) + end + + private + + # Look up a User by their ID and return their email address + # + # recipient_id - User ID + # + # Returns a String containing the User's email address. + def recipient(recipient_id) + if recipient = User.find(recipient_id) + recipient.email + end + end + + # Formats arguments into a String suitable for use as an email subject + # + # extra - Extra Strings to be inserted into the subject + # + # Examples + # + # >> subject('Lorem ipsum') + # => "gitlab | Lorem ipsum" + # + # # Automatically inserts Project name when @project is set + # >> @project = Project.last + # => #<Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...> + # >> subject('Lorem ipsum') + # => "gitlab | Lorem ipsum | Ruby on Rails" + # + # # Accepts multiple arguments + # >> subject('Lorem ipsum', 'Dolor sit amet') + # => "gitlab | Lorem ipsum | Dolor sit amet" + def subject(*extra) + "gitlab | " << extra.join(' | ') << (@project ? " | #{@project.name}" : "") end end diff --git a/app/models/commit.rb b/app/models/commit.rb index 800ad19b9f1..5c6b4d88d96 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -20,7 +20,7 @@ class Commit :tree, :id, :to_patch, - :to => :commit + to: :commit class << self @@ -57,7 +57,7 @@ class Commit def commits_since(repo, date) commits = repo.heads.map do |h| - repo.log(h.name, nil, :since => date).each { |c| Commit.new(c, h) } + repo.log(h.name, nil, since: date).each { |c| Commit.new(c, h) } end.flatten.uniq { |c| c.id } commits.sort! do |x, y| @@ -69,7 +69,7 @@ class Commit def commits(repo, ref, path = nil, limit = nil, offset = nil) if path - repo.log(ref, path, :max_count => limit, :skip => offset) + repo.log(ref, path, max_count: limit, skip: offset) elsif limit && offset repo.commits(ref, limit, offset) else @@ -80,6 +80,29 @@ class Commit def commits_between(repo, from, to) repo.commits_between(from, to).map { |c| Commit.new(c) } end + + def compare(project, from, to) + first = project.commit(to.try(:strip)) + last = project.commit(from.try(:strip)) + + result = { + commits: [], + diffs: [], + commit: nil + } + + if first && last + commits = [first, last].sort_by(&:created_at) + younger = commits.first + older = commits.last + + result[:commits] = project.repo.commits_between(younger.id, older.id).map {|c| Commit.new(c)} + result[:diffs] = project.repo.diff(younger.id, older.id) rescue [] + result[:commit] = Commit.new(older) + end + + result + end end def persisted? @@ -91,6 +114,10 @@ class Commit @head = head end + def short_id(length = 10) + id.to_s[0..length] + end + def safe_message utf8 message end @@ -127,4 +154,8 @@ class Commit def prev_commit_id prev_commit.try :id end + + def parents_count + parents && parents.count || 0 + end end diff --git a/app/models/event.rb b/app/models/event.rb index dc7dfa16dd5..e20b79e2a82 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -12,13 +12,13 @@ class Event < ActiveRecord::Base Merged = 7 belongs_to :project - belongs_to :target, :polymorphic => true + belongs_to :target, polymorphic: true # For Hash only serialize :data scope :recent, order("created_at DESC") - scope :code_push, where(:action => Pushed) + scope :code_push, where(action: Pushed) def self.determine_action(record) if [Issue, MergeRequest].include? record.class @@ -28,6 +28,10 @@ class Event < ActiveRecord::Base end end + def self.recent_for_user user + where(project_id: user.projects.map(&:id)).recent + end + # Next events currently enabled for system # - push # - new issue @@ -102,9 +106,9 @@ class Event < ActiveRecord::Base end end - delegate :name, :email, :to => :author, :prefix => true, :allow_nil => true - delegate :title, :to => :issue, :prefix => true, :allow_nil => true - delegate :title, :to => :merge_request, :prefix => true, :allow_nil => true + delegate :name, :email, to: :author, prefix: true, allow_nil: true + delegate :title, to: :issue, prefix: true, allow_nil: true + delegate :title, to: :merge_request, prefix: true, allow_nil: true end # == Schema Information # diff --git a/app/models/issue.rb b/app/models/issue.rb index 7f935900911..6409eebac63 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -1,60 +1,18 @@ class Issue < ActiveRecord::Base + include IssueCommonality include Upvote acts_as_taggable_on :labels - belongs_to :project belongs_to :milestone - belongs_to :author, :class_name => "User" - belongs_to :assignee, :class_name => "User" - has_many :notes, :as => :noteable, :dependent => :destroy - - attr_protected :author, :author_id, :project, :project_id - attr_accessor :author_id_of_changes - - validates_presence_of :project_id - validates_presence_of :author_id - - delegate :name, - :email, - :to => :author, - :prefix => true - - delegate :name, - :email, - :to => :assignee, - :allow_nil => true, - :prefix => true - - validates :title, - :presence => true, - :length => { :within => 0..255 } validates :description, - :length => { :within => 0..2000 } - - scope :opened, where(:closed => false) - scope :closed, where(:closed => true) - scope :assigned, lambda { |u| where(:assignee_id => u.id)} - - acts_as_list + length: { within: 0..2000 } def self.open_for(user) opened.assigned(user) end - def self.search query - where("title like :query", :query => "%#{query}%") - end - - def today? - Date.today == created_at.to_date - end - - def new? - today? && created_at == updated_at - end - def is_assigned? !!assignee_id end diff --git a/app/models/key.rb b/app/models/key.rb index 6b90b315d82..cfcb1f63c26 100644 --- a/app/models/key.rb +++ b/app/models/key.rb @@ -6,16 +6,16 @@ class Key < ActiveRecord::Base belongs_to :project validates :title, - :presence => true, - :length => { :within => 0..255 } + presence: true, + length: { within: 0..255 } validates :key, - :presence => true, - :length => { :within => 0..5000 } + presence: true, + length: { within: 0..5000 } before_save :set_identifier before_validation :strip_white_space - delegate :name, :email, :to => :user, :prefix => true + delegate :name, :email, to: :user, prefix: true validate :unique_key def strip_white_space @@ -23,7 +23,7 @@ class Key < ActiveRecord::Base end def unique_key - query = Key.where(:key => key) + query = Key.where(key: key) query = query.where('(project_id IS NULL OR project_id = ?)', project_id) if project_id if (query.count > 0) errors.add :key, 'already exist.' diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 2581f3be4c9..542817b0eea 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -1,6 +1,7 @@ require File.join(Rails.root, "app/models/commit") class MergeRequest < ActiveRecord::Base + include IssueCommonality include Upvote BROKEN_DIFF = "--broken-diff" @@ -9,49 +10,17 @@ class MergeRequest < ActiveRecord::Base CAN_BE_MERGED = 2 CANNOT_BE_MERGED = 3 - belongs_to :project - belongs_to :author, :class_name => "User" - belongs_to :assignee, :class_name => "User" - has_many :notes, :as => :noteable, :dependent => :destroy - serialize :st_commits serialize :st_diffs - attr_protected :author, :author_id, :project, :project_id - attr_accessor :author_id_of_changes, - :should_remove_source_branch + attr_accessor :should_remove_source_branch - validates_presence_of :project_id - validates_presence_of :author_id validates_presence_of :source_branch validates_presence_of :target_branch validate :validate_branches - delegate :name, - :email, - :to => :author, - :prefix => true - - delegate :name, - :email, - :to => :assignee, - :allow_nil => true, - :prefix => true - - validates :title, - :presence => true, - :length => { :within => 0..255 } - - scope :opened, where(:closed => false) - scope :closed, where(:closed => true) - scope :assigned, lambda { |u| where(:assignee_id => u.id)} - - def self.search query - where("title like :query", :query => "%#{query}%") - end - def self.find_all_by_branch(branch_name) - where("source_branch like :branch or target_branch like :branch", :branch => branch_name) + where("source_branch like :branch or target_branch like :branch", branch: branch_name) end def human_state @@ -79,7 +48,7 @@ class MergeRequest < ActiveRecord::Base end def mark_as_unchecked - self.update_attributes(:state => UNCHECKED) + self.update_attributes(state: UNCHECKED) end def can_be_merged? @@ -95,14 +64,6 @@ class MergeRequest < ActiveRecord::Base self.save end - def today? - Date.today == created_at.to_date - end - - def new? - today? && created_at == updated_at - end - def diffs st_diffs || [] end @@ -127,24 +88,27 @@ class MergeRequest < ActiveRecord::Base end def unmerged_diffs - commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)} - diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) rescue [] + # Only show what is new in the source branch compared to the target branch, not the other way around. + # The linex below with merge_base is equivalent to diff with three dots (git diff branch1...branch2) + # From the git documentation: "git diff A...B" is equivalent to "git diff $(git-merge-base A B) B" + common_commit = project.repo.git.native(:merge_base, {}, [target_branch, source_branch]).strip + diffs = project.repo.diff(common_commit, source_branch) end def last_commit commits.first end - def merged? + def merged? merged && merge_event end def merge_event - self.project.events.where(:target_id => self.id, :target_type => "MergeRequest", :action => Event::Merged).last + self.project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::Merged).last end def closed_event - self.project.events.where(:target_id => self.id, :target_type => "MergeRequest", :action => Event::Closed).last + self.project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::Closed).last end def commits @@ -152,7 +116,7 @@ class MergeRequest < ActiveRecord::Base end def probably_merged? - unmerged_commits.empty? && + unmerged_commits.empty? && commits.any? && open? end @@ -167,11 +131,11 @@ class MergeRequest < ActiveRecord::Base end def mark_as_unmergable - self.update_attributes :state => CANNOT_BE_MERGED + self.update_attributes state: CANNOT_BE_MERGED end - def reloaded_commits - if open? && unmerged_commits.any? + def reloaded_commits + if open? && unmerged_commits.any? self.st_commits = unmerged_commits save end @@ -189,11 +153,11 @@ class MergeRequest < ActiveRecord::Base def merge!(user_id) self.mark_as_merged! Event.create( - :project => self.project, - :action => Event::Merged, - :target_id => self.id, - :target_type => "MergeRequest", - :author_id => user_id + project: self.project, + action: Event::Merged, + target_id: self.id, + target_type: "MergeRequest", + author_id: user_id ) end diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 7fdfe29edc8..d416fb630c5 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -24,21 +24,13 @@ class Milestone < ActiveRecord::Base end def participants - User.where(:id => issues.map(&:assignee_id)) + User.where(id: issues.map(&:assignee_id)) end def percent_complete - @percent_complete ||= begin - total_i = self.issues.count - closed_i = self.issues.closed.count - if total_i > 0 - (closed_i * 100) / total_i - else - 100 - end - rescue => ex - 0 - end + ((self.issues.closed.count * 100) / self.issues.count).abs + rescue ZeroDivisionError + 100 end def expires_at diff --git a/app/models/note.rb b/app/models/note.rb index 8a26cd05b44..711a4ee6935 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -3,18 +3,18 @@ require 'file_size_validator' class Note < ActiveRecord::Base belongs_to :project - belongs_to :noteable, :polymorphic => true + belongs_to :noteable, polymorphic: true belongs_to :author, - :class_name => "User" + class_name: "User" delegate :name, - :to => :project, - :prefix => true + to: :project, + prefix: true delegate :name, :email, - :to => :author, - :prefix => true + to: :author, + prefix: true attr_protected :author, :author_id attr_accessor :notify @@ -23,19 +23,19 @@ class Note < ActiveRecord::Base validates_presence_of :project validates :note, - :presence => true, - :length => { :within => 0..5000 } + presence: true, + length: { within: 0..5000 } validates :attachment, - :file_size => { - :maximum => 10.megabytes.to_i + file_size: { + maximum: 10.megabytes.to_i } - scope :common, where(:noteable_id => nil) + scope :common, where(noteable_id: nil) - scope :today, where("created_at >= :date", :date => Date.today) - scope :last_week, where("created_at >= :date", :date => (Date.today - 7.days)) - scope :since, lambda { |day| where("created_at >= :date", :date => (day)) } + scope :today, where("created_at >= :date", date: Date.today) + scope :last_week, where("created_at >= :date", date: (Date.today - 7.days)) + scope :since, lambda { |day| where("created_at >= :date", date: (day)) } scope :fresh, order("created_at DESC") scope :inc_author_project, includes(:project, :author) scope :inc_author, includes(:author) @@ -43,11 +43,11 @@ class Note < ActiveRecord::Base mount_uploader :attachment, AttachmentUploader def self.create_status_change_note(noteable, author, status) - create({ :noteable => noteable, - :project => noteable.project, - :author => author, - :note => "_Status changed to #{status}_" }, - :without_protection => true) + create({ noteable: noteable, + project: noteable.project, + author: author, + note: "_Status changed to #{status}_" }, + without_protection: true) end def notify diff --git a/app/models/project.rb b/app/models/project.rb index ec4893e2b17..3fe11916504 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -2,26 +2,26 @@ require "grit" class Project < ActiveRecord::Base include Repository - include GitPush + include PushObserver include Authority include Team # # Relations # - belongs_to :owner, :class_name => "User" - has_many :users, :through => :users_projects - has_many :events, :dependent => :destroy - has_many :merge_requests, :dependent => :destroy - has_many :issues, :dependent => :destroy, :order => "closed, created_at DESC" - has_many :milestones, :dependent => :destroy - has_many :users_projects, :dependent => :destroy - has_many :notes, :dependent => :destroy - has_many :snippets, :dependent => :destroy - has_many :deploy_keys, :dependent => :destroy, :foreign_key => "project_id", :class_name => "Key" - has_many :web_hooks, :dependent => :destroy - has_many :wikis, :dependent => :destroy - has_many :protected_branches, :dependent => :destroy + belongs_to :owner, class_name: "User" + has_many :users, through: :users_projects + has_many :events, dependent: :destroy + has_many :merge_requests, dependent: :destroy + has_many :issues, dependent: :destroy, order: "closed, created_at DESC" + has_many :milestones, dependent: :destroy + has_many :users_projects, dependent: :destroy + has_many :notes, dependent: :destroy + has_many :snippets, dependent: :destroy + has_many :deploy_keys, dependent: :destroy, foreign_key: "project_id", class_name: "Key" + has_many :hooks, dependent: :destroy, class_name: "ProjectHook" + has_many :wikis, dependent: :destroy + has_many :protected_branches, dependent: :destroy attr_accessor :error_code @@ -33,15 +33,15 @@ class Project < ActiveRecord::Base # # Scopes # - scope :public_only, where(:private_flag => false) - scope :without_user, lambda { |user| where("id not in (:ids)", :ids => user.projects.map(&:id) ) } + scope :public_only, where(private_flag: false) + scope :without_user, lambda { |user| where("id not in (:ids)", ids: user.projects.map(&:id) ) } def self.active joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC") end def self.search query - where("name like :query or code like :query or path like :query", :query => "%#{query}%") + where("name like :query or code like :query or path like :query", query: "%#{query}%") end def self.create_by_user(params, user) @@ -53,7 +53,7 @@ class Project < ActiveRecord::Base project.save! # Add user as project master - project.users_projects.create!(:project_access => UsersProject::MASTER, :user => user) + project.users_projects.create!(project_access: UsersProject::MASTER, user: user) # when project saved no team member exist so # project repository should be updated after first user add @@ -66,7 +66,7 @@ class Project < ActiveRecord::Base project rescue => ex project.error_code = :db - project.errors.add(:base, "Cant save project. Please try again later") + project.errors.add(:base, "Can't save project. Please try again later") project end @@ -82,28 +82,28 @@ class Project < ActiveRecord::Base # Validations # validates :name, - :uniqueness => true, - :presence => true, - :length => { :within => 0..255 } + uniqueness: true, + presence: true, + length: { within: 0..255 } validates :path, - :uniqueness => true, - :presence => true, - :format => { :with => /^[a-zA-Z][a-zA-Z0-9_\-\.]*$/, - :message => "only letters, digits & '_' '-' '.' allowed. Letter should be first" }, - :length => { :within => 0..255 } + uniqueness: true, + presence: true, + format: { with: /^[a-zA-Z][a-zA-Z0-9_\-\.]*$/, + message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }, + length: { within: 0..255 } validates :description, - :length => { :within => 0..2000 } + length: { within: 0..2000 } validates :code, - :presence => true, - :uniqueness => true, - :format => { :with => /^[a-zA-Z][a-zA-Z0-9_\-\.]*$/, - :message => "only letters, digits & '_' '-' '.' allowed. Letter should be first" }, - :length => { :within => 1..255 } + presence: true, + uniqueness: true, + format: { with: /^[a-zA-Z][a-zA-Z0-9_\-\.]*$/, + message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }, + length: { within: 1..255 } - validates :owner, :presence => true + validates :owner, presence: true validate :check_limit validate :repo_name @@ -112,7 +112,7 @@ class Project < ActiveRecord::Base errors[:base] << ("Your own projects limit is #{owner.projects_limit}! Please contact administrator to increase it") end rescue - errors[:base] << ("Cant check your ability to create project") + errors[:base] << ("Can't check your ability to create project") end def repo_name @@ -120,7 +120,7 @@ class Project < ActiveRecord::Base errors.add(:path, " like 'gitolite-admin' is not allowed") end end - + def self.access_options UsersProject.access_roles end @@ -134,19 +134,19 @@ class Project < ActiveRecord::Base end def common_notes - notes.where(:noteable_type => ["", nil]).inc_author_project + notes.where(noteable_type: ["", nil]).inc_author_project end def build_commit_note(commit) - notes.new(:noteable_id => commit.id, :noteable_type => "Commit") + notes.new(noteable_id: commit.id, noteable_type: "Commit") end def commit_notes(commit) - notes.where(:noteable_id => commit.id, :noteable_type => "Commit", :line_code => nil) + notes.where(noteable_id: commit.id, noteable_type: "Commit", line_code: nil) end def commit_line_notes(commit) - notes.where(:noteable_id => commit.id, :noteable_type => "Commit").where("line_code is not null") + notes.where(noteable_id: commit.id, noteable_type: "Commit").where("line_code is not null") end def public? diff --git a/app/models/project_hook.rb b/app/models/project_hook.rb new file mode 100644 index 00000000000..06388aaeb4c --- /dev/null +++ b/app/models/project_hook.rb @@ -0,0 +1,3 @@ +class ProjectHook < WebHook + belongs_to :project +end diff --git a/app/models/snippet.rb b/app/models/snippet.rb index e5f04bb228b..2c941499f1f 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -2,29 +2,29 @@ class Snippet < ActiveRecord::Base include Linguist::BlobHelper belongs_to :project - belongs_to :author, :class_name => "User" - has_many :notes, :as => :noteable, :dependent => :destroy + belongs_to :author, class_name: "User" + has_many :notes, as: :noteable, dependent: :destroy delegate :name, :email, - :to => :author, - :prefix => true + to: :author, + prefix: true attr_protected :author, :author_id, :project, :project_id validates_presence_of :project_id validates_presence_of :author_id validates :title, - :presence => true, - :length => { :within => 0..255 } + presence: true, + length: { within: 0..255 } validates :file_name, - :presence => true, - :length => { :within => 0..255 } + presence: true, + length: { within: 0..255 } validates :content, - :presence => true, - :length => { :within => 0..10000 } + presence: true, + length: { within: 0..10000 } scope :fresh, order("created_at DESC") scope :non_expired, where(["expires_at IS NULL OR expires_at > ?", Time.current]) diff --git a/app/models/system_hook.rb b/app/models/system_hook.rb new file mode 100644 index 00000000000..8517d43a9de --- /dev/null +++ b/app/models/system_hook.rb @@ -0,0 +1,13 @@ +class SystemHook < WebHook + + def async_execute(data) + Resque.enqueue(SystemHookWorker, id, data) + end + + def self.all_hooks_fire(data) + SystemHook.all.each do |sh| + sh.async_execute data + end + end + +end diff --git a/app/models/tree.rb b/app/models/tree.rb index 9d60f83015f..bc95d335520 100644 --- a/app/models/tree.rb +++ b/app/models/tree.rb @@ -11,7 +11,7 @@ class Tree :size, :text?, :colorize, - :to => :tree + to: :tree def initialize(raw_tree, project, ref = nil, path = nil) @project, @ref, @path = project, ref, path, diff --git a/app/models/user.rb b/app/models/user.rb index 0836ca4919f..ad6af6a6dd0 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,4 +1,5 @@ class User < ActiveRecord::Base + include Account devise :database_authenticatable, :token_authenticatable, :lockable, @@ -6,62 +7,64 @@ class User < ActiveRecord::Base attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name, :projects_limit, :skype, :linkedin, :twitter, :dark_scheme, - :theme_id, :force_random_password + :theme_id, :force_random_password, :extern_uid, :provider attr_accessor :force_random_password - has_many :users_projects, :dependent => :destroy - has_many :projects, :through => :users_projects - has_many :my_own_projects, :class_name => "Project", :foreign_key => :owner_id - has_many :keys, :dependent => :destroy + has_many :users_projects, dependent: :destroy + has_many :projects, through: :users_projects + has_many :my_own_projects, class_name: "Project", foreign_key: :owner_id + has_many :keys, dependent: :destroy has_many :events, - :class_name => "Event", - :foreign_key => :author_id, - :dependent => :destroy + class_name: "Event", + foreign_key: :author_id, + dependent: :destroy has_many :recent_events, - :class_name => "Event", - :foreign_key => :author_id, - :order => "id DESC" + class_name: "Event", + foreign_key: :author_id, + order: "id DESC" has_many :issues, - :foreign_key => :author_id, - :dependent => :destroy + foreign_key: :author_id, + dependent: :destroy has_many :notes, - :foreign_key => :author_id, - :dependent => :destroy + foreign_key: :author_id, + dependent: :destroy has_many :assigned_issues, - :class_name => "Issue", - :foreign_key => :assignee_id, - :dependent => :destroy + class_name: "Issue", + foreign_key: :assignee_id, + dependent: :destroy has_many :merge_requests, - :foreign_key => :author_id, - :dependent => :destroy + foreign_key: :author_id, + dependent: :destroy has_many :assigned_merge_requests, - :class_name => "MergeRequest", - :foreign_key => :assignee_id, - :dependent => :destroy + class_name: "MergeRequest", + foreign_key: :assignee_id, + dependent: :destroy validates :projects_limit, - :presence => true, - :numericality => {:greater_than_or_equal_to => 0} + presence: true, + numericality: {greater_than_or_equal_to: 0} + + validates :bio, length: { within: 0..255 } - validates :bio, :length => { :within => 0..255 } + validates :extern_uid, :allow_blank => true, :uniqueness => {:scope => :provider} before_save :ensure_authentication_token alias_attribute :private_token, :authentication_token - scope :not_in_project, lambda { |project| where("id not in (:ids)", :ids => project.users.map(&:id) ) } - scope :admins, where(:admin => true) - scope :blocked, where(:blocked => true) - scope :active, where(:blocked => false) + scope :not_in_project, lambda { |project| where("id not in (:ids)", ids: project.users.map(&:id) ) } + scope :admins, where(admin: true) + scope :blocked, where(blocked: true) + scope :active, where(blocked: false) - before_validation :generate_password, :on => :create + before_validation :generate_password, on: :create def generate_password if self.force_random_password @@ -83,16 +86,26 @@ class User < ActiveRecord::Base where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') end - def self.find_for_ldap_auth(omniauth_info) - name = omniauth_info.name.force_encoding("utf-8") - email = omniauth_info.email.downcase unless omniauth_info.email.nil? - raise OmniAuth::Error, "LDAP accounts must provide an email address" if email.nil? + def self.find_for_ldap_auth(auth, signed_in_resource=nil) + uid = auth.info.uid + provider = auth.provider + name = auth.info.name.force_encoding("utf-8") + email = auth.info.email.downcase unless auth.info.email.nil? + raise OmniAuth::Error, "LDAP accounts must provide an uid and email address" if uid.nil? or email.nil? - if @user = User.find_by_email(email) + if @user = User.find_by_extern_uid_and_provider(uid, provider) + @user + # workaround for backward compatibility + elsif @user = User.find_by_email(email) + logger.info "Updating legacy LDAP user #{email} with extern_uid => #{uid}" + @user.update_attributes(:extern_uid => uid, :provider => provider) @user else + logger.info "Creating user from LDAP login {uid => #{uid}, name => #{name}, email => #{email}}" password = Devise.friendly_token[0, 8].downcase @user = User.create( + :extern_uid => uid, + :provider => provider, :name => name, :email => email, :password => password, @@ -103,7 +116,7 @@ class User < ActiveRecord::Base end def self.search query - where("name like :query or email like :query", :query => "%#{query}%") + where("name like :query or email like :query", query: "%#{query}%") end end # == Schema Information diff --git a/app/models/users_project.rb b/app/models/users_project.rb index 6ba72370931..36e6d9045b6 100644 --- a/app/models/users_project.rb +++ b/app/models/users_project.rb @@ -12,18 +12,18 @@ class UsersProject < ActiveRecord::Base after_save :update_repository after_destroy :update_repository - validates_uniqueness_of :user_id, :scope => [:project_id] + validates_uniqueness_of :user_id, scope: [:project_id] validates_presence_of :user_id validates_presence_of :project_id - delegate :name, :email, :to => :user, :prefix => true + delegate :name, :email, to: :user, prefix: true def self.bulk_import(project, user_ids, project_access) UsersProject.transaction do user_ids.each do |user_id| users_project = UsersProject.new( - :project_access => project_access, - :user_id => user_id + project_access: project_access, + user_id: user_id ) users_project.project = project users_project.save @@ -35,7 +35,7 @@ class UsersProject < ActiveRecord::Base UsersProject.transaction do project_ids.each do |project_id| users_project = UsersProject.new( - :project_access => project_access, + project_access: project_access, ) users_project.project_id = project_id users_project.user_id = user.id @@ -68,7 +68,7 @@ class UsersProject < ActiveRecord::Base end def repo_access_human - "" + self.class.access_roles.invert[self.project_access] end end # == Schema Information diff --git a/app/models/web_hook.rb b/app/models/web_hook.rb index 26288476a6c..76efa50198b 100644 --- a/app/models/web_hook.rb +++ b/app/models/web_hook.rb @@ -4,8 +4,6 @@ class WebHook < ActiveRecord::Base # HTTParty timeout default_timeout 10 - belongs_to :project - validates :url, presence: true, format: { @@ -13,10 +11,18 @@ class WebHook < ActiveRecord::Base message: "should be a valid url" } def execute(data) - WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" }) - rescue - # There was a problem calling this web hook, let's forget about it. + parsed_url = URI.parse(url) + if parsed_url.userinfo.blank? + WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" }) + else + post_url = url.gsub(parsed_url.userinfo+"@", "") + WebHook.post(post_url, + body: data.to_json, + headers: { "Content-Type" => "application/json" }, + basic_auth: {username: parsed_url.user, password: parsed_url.password}) + end end + end # == Schema Information # diff --git a/app/models/wiki.rb b/app/models/wiki.rb index ecc46fb4efb..3c4952cd291 100644 --- a/app/models/wiki.rb +++ b/app/models/wiki.rb @@ -1,9 +1,10 @@ class Wiki < ActiveRecord::Base belongs_to :project belongs_to :user + has_many :notes, as: :noteable, dependent: :destroy - validates :content, :title, :user_id, :presence => true - validates :title, :length => 1..250 + validates :content, :title, :user_id, presence: true + validates :title, length: 1..250 before_update :set_slug diff --git a/app/observers/activity_observer.rb b/app/observers/activity_observer.rb index 324d8207d22..48351bac667 100644 --- a/app/observers/activity_observer.rb +++ b/app/observers/activity_observer.rb @@ -3,22 +3,22 @@ class ActivityObserver < ActiveRecord::Observer def after_create(record) Event.create( - :project => record.project, - :target_id => record.id, - :target_type => record.class.name, - :action => Event.determine_action(record), - :author_id => record.author_id + project: record.project, + target_id: record.id, + target_type: record.class.name, + action: Event.determine_action(record), + author_id: record.author_id ) end def after_save(record) if record.changed.include?("closed") Event.create( - :project => record.project, - :target_id => record.id, - :target_type => record.class.name, - :action => (record.closed ? Event::Closed : Event::Reopened), - :author_id => record.author_id_of_changes + project: record.project, + target_id: record.id, + target_type: record.class.name, + action: (record.closed ? Event::Closed : Event::Reopened), + author_id: record.author_id_of_changes ) end end diff --git a/app/observers/mailer_observer.rb b/app/observers/mailer_observer.rb index 451deccd14f..331aaa35e3d 100644 --- a/app/observers/mailer_observer.rb +++ b/app/observers/mailer_observer.rb @@ -34,6 +34,7 @@ class MailerObserver < ActiveRecord::Observer case note.noteable_type when "Commit"; Notify.note_commit_email(u.id, note.id).deliver when "Issue"; Notify.note_issue_email(u.id, note.id).deliver + when "Wiki"; Notify.note_wiki_email(u.id, note.id).deliver when "MergeRequest"; Notify.note_merge_request_email(u.id, note.id).deliver when "Snippet"; true else @@ -70,7 +71,7 @@ class MailerObserver < ActiveRecord::Observer # Create comment about status changed if target.closed_changed? - note = Note.new(:noteable => target, :project => target.project) + note = Note.new(noteable: target, project: target.project) note.author = current_user note.note = "_Status changed to #{target.closed ? 'closed' : 'reopened'}_" note.save() diff --git a/app/observers/system_hook_observer.rb b/app/observers/system_hook_observer.rb new file mode 100644 index 00000000000..312cd2b3622 --- /dev/null +++ b/app/observers/system_hook_observer.rb @@ -0,0 +1,67 @@ +class SystemHookObserver < ActiveRecord::Observer + observe :user, :project, :users_project + + def after_create(model) + if model.kind_of? Project + SystemHook.all_hooks_fire({ + event_name: "project_create", + name: model.name, + path: model.path, + project_id: model.id, + owner_name: model.owner.name, + owner_email: model.owner.email, + created_at: model.created_at + }) + elsif model.kind_of? User + SystemHook.all_hooks_fire({ + event_name: "user_create", + name: model.name, + email: model.email, + created_at: model.created_at + }) + + elsif model.kind_of? UsersProject + SystemHook.all_hooks_fire({ + event_name: "user_add_to_team", + project_name: model.project.name, + project_path: model.project.path, + project_id: model.project_id, + user_name: model.user.name, + user_email: model.user.email, + project_access: model.repo_access_human, + created_at: model.created_at + }) + + end + end + + def after_destroy(model) + if model.kind_of? Project + SystemHook.all_hooks_fire({ + event_name: "project_destroy", + name: model.name, + path: model.path, + project_id: model.id, + owner_name: model.owner.name, + owner_email: model.owner.email, + }) + elsif model.kind_of? User + SystemHook.all_hooks_fire({ + event_name: "user_destroy", + name: model.name, + email: model.email + }) + + elsif model.kind_of? UsersProject + SystemHook.all_hooks_fire({ + event_name: "user_remove_from_team", + project_name: model.project.name, + project_path: model.project.path, + project_id: model.project_id, + user_name: model.user.name, + user_email: model.user.email, + project_access: model.repo_access_human + }) + end + end +end diff --git a/app/roles/account.rb b/app/roles/account.rb index afa1f8a347d..63a9b5c51bf 100644 --- a/app/roles/account.rb +++ b/app/roles/account.rb @@ -1,6 +1,6 @@ module Account def identifier - email.gsub /[@.]/, "_" + email.gsub /[^[:alnum:]]/, "_" end def is_admin? @@ -24,7 +24,7 @@ module Account end def cared_merge_requests - MergeRequest.where("author_id = :id or assignee_id = :id", :id => self.id).opened + MergeRequest.where("author_id = :id or assignee_id = :id", id: self.id).opened end def project_ids @@ -50,9 +50,13 @@ module Account def recent_push project_id = nil # Get push events not earlier than 2 hours ago events = recent_events.code_push.where("created_at > ?", Time.now - 2.hours) - events = events.where(:project_id => project_id) if project_id + events = events.where(project_id: project_id) if project_id # Take only latest one events = events.recent.limit(1).first end + + def projects_with_events + projects.includes(:events).order("events.created_at DESC") + end end diff --git a/app/roles/authority.rb b/app/roles/authority.rb index a03b54a3ee7..9d9153db66e 100644 --- a/app/roles/authority.rb +++ b/app/roles/authority.rb @@ -3,56 +3,56 @@ module Authority # Should be rewrited for new access rights def add_access(user, *access) access = if access.include?(:admin) - { :project_access => UsersProject::MASTER } + { project_access: UsersProject::MASTER } elsif access.include?(:write) - { :project_access => UsersProject::DEVELOPER } + { project_access: UsersProject::DEVELOPER } else - { :project_access => UsersProject::REPORTER } + { project_access: UsersProject::REPORTER } end - opts = { :user => user } + opts = { user: user } opts.merge!(access) users_projects.create(opts) end def reset_access(user) - users_projects.where(:project_id => self.id, :user_id => user.id).destroy if self.id + users_projects.where(project_id: self.id, user_id: user.id).destroy if self.id end def repository_readers - keys = Key.joins({:user => :users_projects}). + keys = Key.joins({user: :users_projects}). where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::REPORTER) keys.map(&:identifier) + deploy_keys.map(&:identifier) end def repository_writers - keys = Key.joins({:user => :users_projects}). + keys = Key.joins({user: :users_projects}). where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::DEVELOPER) keys.map(&:identifier) end def repository_masters - keys = Key.joins({:user => :users_projects}). + keys = Key.joins({user: :users_projects}). where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::MASTER) keys.map(&:identifier) end def allow_read_for?(user) - !users_projects.where(:user_id => user.id).empty? + !users_projects.where(user_id: user.id).empty? end def guest_access_for?(user) - !users_projects.where(:user_id => user.id).empty? + !users_projects.where(user_id: user.id).empty? end def report_access_for?(user) - !users_projects.where(:user_id => user.id, :project_access => [UsersProject::REPORTER, UsersProject::DEVELOPER, UsersProject::MASTER]).empty? + !users_projects.where(user_id: user.id, project_access: [UsersProject::REPORTER, UsersProject::DEVELOPER, UsersProject::MASTER]).empty? end def dev_access_for?(user) - !users_projects.where(:user_id => user.id, :project_access => [UsersProject::DEVELOPER, UsersProject::MASTER]).empty? + !users_projects.where(user_id: user.id, project_access: [UsersProject::DEVELOPER, UsersProject::MASTER]).empty? end def master_access_for?(user) - !users_projects.where(:user_id => user.id, :project_access => [UsersProject::MASTER]).empty? || owner_id == user.id + !users_projects.where(user_id: user.id, project_access: [UsersProject::MASTER]).empty? || owner_id == user.id end end diff --git a/app/roles/issue_commonality.rb b/app/roles/issue_commonality.rb new file mode 100644 index 00000000000..a8fd679df81 --- /dev/null +++ b/app/roles/issue_commonality.rb @@ -0,0 +1,52 @@ +# Contains common functionality shared between Issues and MergeRequests +module IssueCommonality + extend ActiveSupport::Concern + + included do + attr_protected :author, :author_id, :project, :project_id + + belongs_to :project + belongs_to :author, class_name: "User" + belongs_to :assignee, class_name: "User" + has_many :notes, as: :noteable, dependent: :destroy + + validates_presence_of :project_id + validates_presence_of :author_id + + validates :title, + presence: true, + length: { within: 0..255 } + + + scope :opened, where(closed: false) + scope :closed, where(closed: true) + scope :assigned, lambda { |u| where(assignee_id: u.id)} + + delegate :name, + :email, + to: :author, + prefix: true + + delegate :name, + :email, + to: :assignee, + allow_nil: true, + prefix: true + + attr_accessor :author_id_of_changes + end + + module ClassMethods + def search(query) + where("title like :query", query: "%#{query}%") + end + end + + def today? + Date.today == created_at.to_date + end + + def new? + today? && created_at == updated_at + end +end diff --git a/app/roles/git_push.rb b/app/roles/push_observer.rb index b4c59472a5a..1067404d5af 100644 --- a/app/roles/git_push.rb +++ b/app/roles/push_observer.rb @@ -1,12 +1,12 @@ -module GitPush +module PushObserver def observe_push(oldrev, newrev, ref, user) data = post_receive_data(oldrev, newrev, ref, user) Event.create( - :project => self, - :action => Event::Pushed, - :data => data, - :author_id => data[:user_id] + project: self, + action: Event::Pushed, + data: data, + author_id: data[:user_id] ) end @@ -20,14 +20,14 @@ module GitPush mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked } # Close merge requests - mrs = self.merge_requests.opened.where(:target_branch => branch_name).all + mrs = self.merge_requests.opened.where(target_branch: branch_name).all mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) } mrs.each { |merge_request| merge_request.merge!(user.id) } true end - def execute_web_hooks(oldrev, newrev, ref, user) + def execute_hooks(oldrev, newrev, ref, user) ref_parts = ref.split('/') # Return if this is not a push to a branch (e.g. new commits) @@ -35,7 +35,7 @@ module GitPush data = post_receive_data(oldrev, newrev, ref, user) - web_hooks.each { |web_hook| web_hook.execute(data) } + hooks.each { |hook| hook.execute(data) } end def post_receive_data(oldrev, newrev, ref, user) @@ -97,7 +97,7 @@ module GitPush self.update_merge_requests(oldrev, newrev, ref, user) # Execute web hooks - self.execute_web_hooks(oldrev, newrev, ref, user) + self.execute_hooks(oldrev, newrev, ref, user) # Create satellite self.satellite.create unless self.satellite.exists? diff --git a/app/roles/repository.rb b/app/roles/repository.rb index 8d5b018de77..7f1d6f84549 100644 --- a/app/roles/repository.rb +++ b/app/roles/repository.rb @@ -30,26 +30,10 @@ module Repository Commit.commits_between(repo, from, to) end - def write_hooks - %w(post-receive).each do |hook| - write_hook(hook, File.read(File.join(Rails.root, 'lib', "#{hook}-hook"))) - end - end - def satellite @satellite ||= Gitlab::Satellite.new(self) end - def write_hook(name, content) - hook_file = File.join(path_to_repo, 'hooks', name) - - File.open(hook_file, 'w') do |f| - f.write(content) - end - - File.chmod(0775, hook_file) - end - def has_post_receive_file? hook_file = File.join(path_to_repo, 'hooks', 'post-receive') File.exists?(hook_file) @@ -73,8 +57,6 @@ module Repository def update_repository Gitlab::GitHost.system.update_project(path, self) - - write_hooks if File.exists?(path_to_repo) end def destroy_repository diff --git a/app/roles/ssh_key.rb b/app/roles/ssh_key.rb index f1143c5d065..5e1d2c23d15 100644 --- a/app/roles/ssh_key.rb +++ b/app/roles/ssh_key.rb @@ -9,7 +9,7 @@ module SshKey def repository_delete_key Gitlab::GitHost.system.new.configure do |c| #delete key file is there is no identically deploy keys - if !is_deploy_key || Key.where(:identifier => identifier).count() == 0 + if !is_deploy_key || Key.where(identifier: identifier).count() == 0 c.delete_key(identifier) end c.update_projects(projects) diff --git a/app/roles/team.rb b/app/roles/team.rb index 2a477b6edba..27b1cc65897 100644 --- a/app/roles/team.rb +++ b/app/roles/team.rb @@ -4,7 +4,36 @@ module Team users_projects.find_by_user_id(user.id) if user end + # Get Team Member record by user id def team_member_by_id(user_id) users_projects.find_by_user_id(user_id) end + + # Add user to project + # with passed access role + def add_user_to_team(user, access_role) + add_user_id_to_team(user.id, access_role) + end + + # Add multiple users to project + # with same access role + def add_users_to_team(users, access_role) + add_users_ids_to_team(users.map(&:id), access_role) + end + + # Add user to project + # with passed access role by user id + def add_user_id_to_team(user_id, access_role) + users_projects.create( + user_id: user_id, + project_access: access_role + ) + end + + # Add multiple users to project + # with same access role by user ids + def add_users_ids_to_team(users_ids, access_role) + UsersProject.bulk_import(self, users_ids, access_role) + self.update_repository + end end diff --git a/app/uploaders/attachment_uploader.rb b/app/uploaders/attachment_uploader.rb index 4ba19ace8d1..bb7dc0dab10 100644 --- a/app/uploaders/attachment_uploader.rb +++ b/app/uploaders/attachment_uploader.rb @@ -23,7 +23,7 @@ class AttachmentUploader < CarrierWave::Uploader::Base # end # Process files as they are uploaded: - # process :scale => [200, 300] + # process scale: [200, 300] # # def scale(width, height) # # do something @@ -31,7 +31,7 @@ class AttachmentUploader < CarrierWave::Uploader::Base # Create different versions of your uploaded files: # version :thumb do - # process :scale => [50, 50] + # process scale: [50, 50] # end # Add a white list of extensions which are allowed to be uploaded. diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 886943be6de..3e26f566a2e 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -5,11 +5,11 @@ Resque Workers .data.padded = link_to admin_resque_path do - %h1{:class => @workers.present? ? "cgreen" : "cred"} + %h1{class: @workers.present? ? "cgreen" : "cred"} = @workers.count %hr %p - %strong{:class => @pending_jobs > 0 ? "cred" : "cgreen"} + %strong{class: @pending_jobs > 0 ? "cred" : "cgreen"} #{@pending_jobs} post receive jobs waiting .span4 @@ -19,7 +19,7 @@ = link_to admin_projects_path do %h1= Project.count %hr - = link_to 'New Project', new_admin_project_path, :class => "btn small" + = link_to 'New Project', new_admin_project_path, class: "btn small" .span4 .ui-box %h5 Users @@ -27,7 +27,7 @@ = link_to admin_users_path do %h1= User.count %hr - = link_to 'New User', new_admin_user_path, :class => "btn small" + = link_to 'New User', new_admin_user_path, class: "btn small" .row @@ -35,11 +35,13 @@ %h3 Latest projects %hr - @projects.each do |project| - %h5 + %p = link_to project.name, [:admin, project] .span6 %h3 Latest users %hr - @users.each do |user| - %h5 - = link_to user.name, [:admin, user] + %p + = link_to [:admin, user] do + = user.name + %small= user.email diff --git a/app/views/admin/hooks/_data_ex.html.erb b/app/views/admin/hooks/_data_ex.html.erb new file mode 100644 index 00000000000..652ee5aa56f --- /dev/null +++ b/app/views/admin/hooks/_data_ex.html.erb @@ -0,0 +1,66 @@ +<% data_ex_str = <<eos +1. Project created: +{ + "created_at": "2012-07-21T07:30:54Z", + "event_name": "project_create", + "name": "StoreCloud", + "owner_email": "johnsmith@gmail.com", + "owner_name": "John Smith", + "path": "storecloud", + "project_id": 74 +} + +2. Project destroyed: +{ + "event_name": "project_destroy", + "name": "Underscore", + "owner_email": "johnsmith@gmail.com", + "owner_name": "John Smith", + "path": "underscore", + "project_id": 73 +} + +3. New Team Member: +{ + "created_at": "2012-07-21T07:30:56Z", + "event_name": "user_add_to_team", + "project_access": "Master", + "project_id": 74, + "project_name": "StoreCloud", + "project_path": "storecloud", + "owner_email": "johnsmith@gmail.com", + "owner_name": "John Smith", +} + +4. Team Member Removed: +{ + "created_at": "2012-07-21T07:30:56Z", + "event_name": "user_remove_from_team", + "project_access": "Master", + "project_id": 74, + "project_name": "StoreCloud", + "project_path": "storecloud", + "owner_email": "johnsmith@gmail.com", + "owner_name": "John Smith", +} + +5. User created: +{ + "created_at": "2012-07-21T07:44:07Z", + "email": "js@gitlabhq.com", + "event_name": "user_create", + "name": "John Smith" +} + +6. User removed: +{ + "created_at": "2012-07-21T07:44:07Z", + "email": "js@gitlabhq.com", + "event_name": "user_destroy", + "name": "John Smith" +} + +eos +%> +<% js_lexer = Pygments::Lexer[:js] %> +<%= raw js_lexer.highlight(data_ex_str) %> diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml new file mode 100644 index 00000000000..43288424e8e --- /dev/null +++ b/app/views/admin/hooks/index.html.haml @@ -0,0 +1,39 @@ +.alert.alert-info + %span + Post receive hooks for binding events. + %br + Read more about system hooks + %strong #{link_to "here", help_system_hooks_path, class: "vlink"} + += form_for @hook, as: :hook, url: admin_hooks_path, html: { class: 'form-inline' } do |f| + -if @hook.errors.any? + .alert-message.block-message.error + - @hook.errors.full_messages.each do |msg| + %p= msg + .clearfix + = f.label :url, "URL:" + .input + = f.text_field :url, class: "text_field xxlarge" + + = f.submit "Add System Hook", class: "btn primary" +%hr + +-if @hooks.any? + %h3 + Hooks + %small (#{@hooks.count}) + %br + %table.admin-table + %tr + %th URL + %th Method + %th + - @hooks.each do |hook| + %tr + %td + = link_to admin_hook_path(hook) do + %strong= hook.url + = link_to 'Test Hook', admin_hook_test_path(hook), class: "btn small right" + %td POST + %td + = link_to 'Remove', admin_hook_path(hook), confirm: 'Are you sure?', method: :delete, class: "danger btn small right" diff --git a/app/views/admin/mailer/preview.html.haml b/app/views/admin/mailer/preview.html.haml deleted file mode 100644 index 23ea7381cf5..00000000000 --- a/app/views/admin/mailer/preview.html.haml +++ /dev/null @@ -1,28 +0,0 @@ -%p This is page with preview for all system emails that are sent to user -%p Email previews built based on existing Project/Commit/Issue base - so some preview maybe unavailable unless object appear in system - -#accordion - %h3 - %a New user - %div - %iframe{ :src=> admin_mailer_preview_user_new_path, :width=>"100%", :height=>"350"} - %h3 - %a New issue - %div - %iframe{ :src=> admin_mailer_preview_issue_new_path, :width=>"100%", :height=>"350"} - %h3 - %a Commit note - %div - %iframe{ :src=> admin_mailer_preview_note_path(:type => "Commit"), :width=>"100%", :height=>"350"} - %h3 - %a Issue note - %div - %iframe{ :src=> admin_mailer_preview_note_path(:type => "Issue"), :width=>"100%", :height=>"350"} - %h3 - %a Wall note - %div - %iframe{ :src=> admin_mailer_preview_note_path(:type => "Wall"), :width=>"100%", :height=>"350"} - -:javascript - $(function() { - $("#accordion").accordion(); }); diff --git a/app/views/admin/projects/_form.html.haml b/app/views/admin/projects/_form.html.haml index 41c620a0218..7cebddf2890 100644 --- a/app/views/admin/projects/_form.html.haml +++ b/app/views/admin/projects/_form.html.haml @@ -1,40 +1,49 @@ -= form_for [:admin, @admin_project] do |f| - -if @admin_project.errors.any? += form_for [:admin, project] do |f| + -if project.errors.any? .alert-message.block-message.error %ul - - @admin_project.errors.full_messages.each do |msg| + - project.errors.full_messages.each do |msg| %li= msg - .clearfix - = f.label :name - .input= f.text_field :name - .clearfix - = f.label :path do - Path + .clearfix.project_name_holder + = f.label :name do + Project name is .input - .input-prepend - %span.add-on= Gitlab.config.ssh_path - = f.text_field :path, :placeholder => "example_project", :disabled => !@admin_project.new_record? - .clearfix - = f.label :code do - Code - .input - .input-prepend - %span.add-on= web_app_url - = f.text_field :code, :placeholder => "example" + = f.text_field :name, placeholder: "Example Project", class: "xxlarge" + = f.submit project.new_record? ? 'Create project' : 'Save Project', class: "btn primary" - - unless @admin_project.new_record? + %hr + .alert.alert-info + %h5 Advanced settings: + .clearfix + = f.label :path do + Git Clone + .input + .input-prepend + %span.add-on= Gitlab.config.ssh_path + = f.text_field :path, placeholder: "example_project", disabled: !!project.id + %span.add-on= ".git" .clearfix - = f.label :owner_id - .input= f.select :owner_id, User.all.map { |user| [user.name, user.id] } + = f.label :code do + URL + .input + .input-prepend + %span.add-on= web_app_url + = f.text_field :code, placeholder: "example" - - if @admin_project.repo_exists? + - unless project.new_record? .clearfix - = f.label :default_branch, "Default Branch" - .input= f.select(:default_branch, @admin_project.heads.map(&:name), {}, :style => "width:210px;") + = f.label :owner_id + .input= f.select :owner_id, User.all.map { |user| [user.name, user.id] } - .well - %h5 Features + - if project.repo_exists? + .clearfix + = f.label :default_branch, "Default Branch" + .input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;") + + - unless project.new_record? + .alert.alert-info + %h5 Features: .clearfix = f.label :issues_enabled, "Issues" @@ -48,19 +57,19 @@ = f.label :wall_enabled, "Wall" .input= f.check_box :wall_enabled - .clearfix - = f.label :description - .input= f.text_area :description, :class => "xxlarge" - .clear - %br - .actions - = f.submit 'Save', :class => "btn primary" - = link_to 'Cancel', [:admin, @admin_project], :class => "btn" - - unless @admin_project.new_record? - = link_to 'Destroy', [:admin, @admin_project], :confirm => 'Are you sure?', :method => :delete, :class => "btn danger right" + .clearfix + = f.label :wiki_enabled, "Wiki" + .input= f.check_box :wiki_enabled + + - unless project.new_record? + .actions + = f.submit 'Save Project', class: "btn primary" + + :javascript $(function(){ $('#project_owner_id').chosen(); new Projects(); }) + diff --git a/app/views/admin/projects/edit.html.haml b/app/views/admin/projects/edit.html.haml index b8d6f6899cb..b5255671154 100644 --- a/app/views/admin/projects/edit.html.haml +++ b/app/views/admin/projects/edit.html.haml @@ -1,3 +1,3 @@ -%h3= @admin_project.name +%h3.page_title #{@admin_project.name} → Edit project %hr -= render 'form' += render 'form', project: @admin_project diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index 7218eebb62a..f7dd486ddac 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -1,10 +1,10 @@ -%h3 +%h3.page_title Projects - = link_to 'New Project', new_admin_project_path, :class => "btn small right" + = link_to 'New Project', new_admin_project_path, class: "btn small right" %br -= form_tag admin_projects_path, :method => :get do - = text_field_tag :name, params[:name], :class => "xlarge" - = submit_tag "Search", :class => "btn submit primary" += form_tag admin_projects_path, method: :get, class: 'form-inline' do + = text_field_tag :name, params[:name], class: "xlarge" + = submit_tag "Search", class: "btn submit primary" %table.admin-table %thead @@ -21,8 +21,8 @@ %td= link_to project.name, [:admin, project] %td= project.path %td= project.users_projects.count - %td= check_box_tag :post_receive_file, 1, project.has_post_receive_file?, :disabled => true + %td= check_box_tag :post_receive_file, 1, project.has_post_receive_file?, disabled: true %td= last_commit(project) - %td= link_to 'Edit', edit_admin_project_path(project), :id => "edit_#{dom_id(project)}", :class => "btn small" - %td.bgred= link_to 'Destroy', [:admin, project], :confirm => "REMOVE #{project.name}? Are you sure?", :method => :delete, :class => "btn small danger" -= paginate @admin_projects, :theme => "admin" + %td= link_to 'Edit', edit_admin_project_path(project), id: "edit_#{dom_id(project)}", class: "btn small" + %td.bgred= link_to 'Destroy', [:admin, project], confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn small danger" += paginate @admin_projects, theme: "admin" diff --git a/app/views/admin/projects/new.html.haml b/app/views/admin/projects/new.html.haml index 1e1c7aac46e..ac6526bfa4b 100644 --- a/app/views/admin/projects/new.html.haml +++ b/app/views/admin/projects/new.html.haml @@ -1,3 +1,3 @@ -%h2 New project +%h3.page_title New project %hr -= render 'form' += render 'form', project: @admin_project diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index 8ba2943e7f9..5ed56477905 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -1,6 +1,6 @@ %h3 = @admin_project.name - = link_to 'Edit', edit_admin_project_path(@admin_project), :class => "btn right small" + = link_to 'Edit', edit_admin_project_path(@admin_project), class: "btn right small" %br %table.zebra-striped.table-bordered @@ -25,15 +25,15 @@ %tr %td %b - Description: + Owner: %td - = @admin_project.description + = @admin_project.owner.name %tr %td %b Post Receive File: %td - = check_box_tag :post_receive_file, 1, @admin_project.has_post_receive_file?, :disabled => true + = check_box_tag :post_receive_file, 1, @admin_project.has_post_receive_file?, disabled: true %br %h3 Team @@ -52,14 +52,14 @@ %tr %td = link_to tm.user_name, admin_user_path(tm.user) - %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), :class => "medium project-access-select", :disabled => :disabled - %td= link_to 'Edit Access', edit_admin_team_member_path(tm), :class => "btn small" - %td= link_to 'Remove from team', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete, :class => "btn danger small" + %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), class: "medium project-access-select", disabled: :disabled + %td= link_to 'Edit Access', edit_admin_team_member_path(tm), class: "btn small" + %td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn danger small" %br %h3 Add new team member %br -= form_tag team_update_admin_project_path(@admin_project), :class => "bulk_import", :method => :put do += form_tag team_update_admin_project_path(@admin_project), class: "bulk_import", method: :put do %table.zebra-striped.table-bordered %thead %tr @@ -67,14 +67,14 @@ %th Project Access: %tr - %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), :multiple => true - %td= select_tag :project_access, options_for_select(Project.access_options), :class => "project-access-select" + %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), multiple: true + %td= select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select" %tr - %td= submit_tag 'Add', :class => "btn primary" + %td= submit_tag 'Add', class: "btn primary" %td Read more about project permissions - %strong= link_to "here", help_permissions_path, :class => "vlink" + %strong= link_to "here", help_permissions_path, class: "vlink" :css form select { diff --git a/app/views/admin/resque/show.html.haml b/app/views/admin/resque/show.html.haml index 267129530bd..0375d94bc9d 100644 --- a/app/views/admin/resque/show.html.haml +++ b/app/views/admin/resque/show.html.haml @@ -1,2 +1,2 @@ %h3 Resque -%iframe{:src => "/info/resque", :width => 1168, :height => 600, :style => "border: none"}
\ No newline at end of file +%iframe{src: "/info/resque", width: 1168, height: 600, style: "border: none"}
\ No newline at end of file diff --git a/app/views/admin/team_members/_form.html.haml b/app/views/admin/team_members/_form.html.haml index 034757620ec..6a128de94b2 100644 --- a/app/views/admin/team_members/_form.html.haml +++ b/app/views/admin/team_members/_form.html.haml @@ -1,4 +1,4 @@ -= form_for @admin_team_member, :as => :team_member, :url => admin_team_member_path(@admin_team_member) do |f| += form_for @admin_team_member, as: :team_member, url: admin_team_member_path(@admin_team_member) do |f| -if @admin_team_member.errors.any? .alert-message.block-message.error %ul @@ -8,12 +8,12 @@ .clearfix %label Project Access: .input - = f.select :project_access, options_for_select(Project.access_options, @admin_team_member.project_access), {}, :class => "project-access-select" + = f.select :project_access, options_for_select(Project.access_options, @admin_team_member.project_access), {}, class: "project-access-select" %br .actions - = f.submit 'Save', :class => "btn primary" - = link_to 'Cancel', :back, :class => "btn" + = f.submit 'Save', class: "btn primary" + = link_to 'Cancel', :back, class: "btn" :css form select { diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml index bd2e136247a..2014472375b 100644 --- a/app/views/admin/users/_form.html.haml +++ b/app/views/admin/users/_form.html.haml @@ -2,71 +2,79 @@ = form_for [:admin, @admin_user] do |f| -if @admin_user.errors.any? #error_explanation - %ul + %ul.unstyled.alert.alert-error - @admin_user.errors.full_messages.each do |msg| %li= msg .row - .span6 - .clearfix - = f.label :name - .input - = f.text_field :name - %span.help-inline * required - .clearfix - = f.label :email - .input - = f.text_field :email - %span.help-inline * required - %hr - - -if f.object.new_record? - .clearfix - = f.label :admin, :class => "checkbox" do - = f.check_box :force_random_password, {}, true, nil - %span Generate random password - - %div.password-fields + .span7 + .ui-box + %br .clearfix - = f.label :password - .input= f.password_field :password, :disabled => f.object.force_random_password + = f.label :name + .input + = f.text_field :name + %span.help-inline * required .clearfix - = f.label :password_confirmation - .input= f.password_field :password_confirmation, :disabled => f.object.force_random_password - %hr - .clearfix - = f.label :skype - .input= f.text_field :skype - .clearfix - = f.label :linkedin - .input= f.text_field :linkedin - .clearfix - = f.label :twitter - .input= f.text_field :twitter - .span6 - .clearfix - = f.label :projects_limit - .input= f.text_field :projects_limit, :class => "small_input" + = f.label :email + .input + = f.text_field :email + %span.help-inline * required + %hr + -if f.object.new_record? + .clearfix + = f.label :force_random_password do + %span Generate random password + .input= f.check_box :force_random_password, {}, true, nil + + %div.password-fields + .clearfix + = f.label :password + .input= f.password_field :password, disabled: f.object.force_random_password + .clearfix + = f.label :password_confirmation + .input= f.password_field :password_confirmation, disabled: f.object.force_random_password + %hr + .clearfix + = f.label :skype + .input= f.text_field :skype + .clearfix + = f.label :linkedin + .input= f.text_field :linkedin + .clearfix + = f.label :twitter + .input= f.text_field :twitter + .span5 + .ui-box + %br + .clearfix + = f.label :projects_limit + .input= f.number_field :projects_limit - .alert .clearfix - %p Give user ability to manage application. - = f.label :admin, :class => "checkbox" do - = f.check_box :admin - %span Administrator - - unless @admin_user.new_record? - .alert.alert-error - - if @admin_user.blocked - %span - = link_to 'Unblock', unblock_admin_user_path(@admin_user), :method => :put, :class => "btn small" - This user is blocked and is not able to login GitLab - - else - %span - = link_to 'Block', block_admin_user_path(@admin_user), :confirm => 'USER WILL BE BLOCKED! Are you sure?', :method => :put, :class => "btn small danger" - Blocked user will removed from all projects & will not be able to login to GitLab. + = f.label :admin do + %strong.cred Administrator + .input= f.check_box :admin + - unless @admin_user.new_record? + %hr + .padded.cred + - if @admin_user.blocked + %span + This user is blocked and is not able to login to GitLab + .clearfix + = link_to 'Unblock User', unblock_admin_user_path(@admin_user), method: :put, class: "btn small right" + - else + %span + Blocked users will be removed from all projects & will not be able to login to GitLab. + .clearfix + = link_to 'Block User', block_admin_user_path(@admin_user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small right danger" + + .row + .span6 + .span6 .actions - = f.submit 'Save', :class => "btn primary" + = f.submit 'Save', class: "btn primary" - if @admin_user.new_record? - = link_to 'Cancel', admin_users_path, :class => "btn" + = link_to 'Cancel', admin_users_path, class: "btn" - else - = link_to 'Cancel', admin_user_path(@admin_user), :class => "btn" + = link_to 'Cancel', admin_user_path(@admin_user), class: "btn" diff --git a/app/views/admin/users/edit.html.haml b/app/views/admin/users/edit.html.haml index 0e94be9e12c..032e3cfaa99 100644 --- a/app/views/admin/users/edit.html.haml +++ b/app/views/admin/users/edit.html.haml @@ -1,3 +1,3 @@ -%h3= @admin_user.name +%h3.page_title #{@admin_user.name} → Edit user %hr = render 'form' diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index 5d5320db0e3..f21baabf8eb 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -1,22 +1,22 @@ -%h3 +%h3.page_title Users - = link_to 'New User', new_admin_user_path, :class => "btn small right" + = link_to 'New User', new_admin_user_path, class: "btn small right" %br -= form_tag admin_users_path, :method => :get do - = text_field_tag :name, params[:name], :class => "xlarge" - = submit_tag "Search", :class => "btn submit primary" += form_tag admin_users_path, method: :get, class: 'form-inline' do + = text_field_tag :name, params[:name], class: "xlarge" + = submit_tag "Search", class: "btn submit primary" %ul.nav.nav-pills - %li{:class => "#{'active' unless params[:filter]}"} + %li{class: "#{'active' unless params[:filter]}"} = link_to "Active", admin_users_path - %li{:class => "#{'active' if params[:filter] == "admins"}"} - = link_to admin_users_path(:filter => "admins") do + %li{class: "#{'active' if params[:filter] == "admins"}"} + = link_to admin_users_path(filter: "admins") do Admins - %li{:class => "#{'active' if params[:filter] == "blocked"}"} - = link_to admin_users_path(:filter => "blocked") do + %li{class: "#{'active' if params[:filter] == "blocked"}"} + = link_to admin_users_path(filter: "blocked") do Blocked - %li{:class => "#{'active' if params[:filter] == "wop"}"} - = link_to admin_users_path(:filter => "wop") do + %li{class: "#{'active' if params[:filter] == "wop"}"} + = link_to admin_users_path(filter: "wop") do Without projects %table.admin-table @@ -31,16 +31,16 @@ - @admin_users.each do |user| %tr - %td= check_box_tag "admin", 1, user.admin, :disabled => :disabled + %td= check_box_tag "admin", 1, user.admin, disabled: :disabled %td= link_to user.name, [:admin, user] %td= user.email %td= user.users_projects.count - %td= link_to 'Edit', edit_admin_user_path(user), :id => "edit_#{dom_id(user)}", :class => "btn small" + %td= link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn small" %td - if user.blocked - = link_to 'Unblock', unblock_admin_user_path(user), :method => :put, :class => "btn small success" + = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn small success" - else - = link_to 'Block', block_admin_user_path(user), :confirm => 'USER WILL BE BLOCKED! Are you sure?', :method => :put, :class => "btn small danger" - %td.bgred= link_to 'Destroy', [:admin, user], :confirm => "USER #{user.name} WILL BE REMOVED! Are you sure?", :method => :delete, :class => "btn small danger" + = link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small danger" + %td.bgred= link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn small danger" -= paginate @admin_users, :theme => "admin" += paginate @admin_users, theme: "admin" diff --git a/app/views/admin/users/new.html.haml b/app/views/admin/users/new.html.haml index 87d6b0f2757..70ead0d3f7d 100644 --- a/app/views/admin/users/new.html.haml +++ b/app/views/admin/users/new.html.haml @@ -1,3 +1,3 @@ -%h2 New user -%hr +%h3.page_title New user +%br = render 'form' diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index 7510b1446dc..4cca8ed7a4e 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -4,7 +4,7 @@ %small Blocked - if @admin_user.admin %small Administrator - = link_to 'Edit', edit_admin_user_path(@admin_user), :class => "btn small right" + = link_to 'Edit', edit_admin_user_path(@admin_user), class: "btn small right" %br @@ -19,12 +19,12 @@ %td %b Admin: - %td= check_box_tag "admin", 1, @admin_user.admin, :disabled => :disabled + %td= check_box_tag "admin", 1, @admin_user.admin, disabled: :disabled %tr %td %b Blocked: - %td= check_box_tag "blocked", 1, @admin_user.blocked, :disabled => :disabled + %td= check_box_tag "blocked", 1, @admin_user.blocked, disabled: :disabled %tr %td %b @@ -56,7 +56,7 @@ %br %h3 Add User to Projects %br -= form_tag team_update_admin_user_path(@admin_user), :class => "bulk_import", :method => :put do += form_tag team_update_admin_user_path(@admin_user), class: "bulk_import", method: :put do %table.table-bordered %thead %tr @@ -64,14 +64,14 @@ %th Project Access: %tr - %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name), :multiple => true - %td= select_tag :project_access, options_for_select(Project.access_options), :class => "project-access-select" + %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name), multiple: true + %td= select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select" %tr - %td= submit_tag 'Add', :class => "btn primary" + %td= submit_tag 'Add', class: "btn primary" %td Read more about project permissions - %strong= link_to "here", help_permissions_path, :class => "vlink" + %strong= link_to "here", help_permissions_path, class: "vlink" %br - if @admin_user.projects.present? @@ -90,9 +90,9 @@ - project = tm.project %tr %td= link_to project.name, admin_project_path(project) - %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), :class => "medium project-access-select", :disabled => :disabled - %td= link_to 'Edit Access', edit_admin_team_member_path(tm), :class => "btn small" - %td= link_to 'Remove from team', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete, :class => "btn small danger" + %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), class: "medium project-access-select", disabled: :disabled + %td= link_to 'Edit Access', edit_admin_team_member_path(tm), class: "btn small" + %td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn small danger" :css form select { diff --git a/app/views/commits/_commit.html.haml b/app/views/commits/_commit.html.haml index 9f9502e30d4..686a4337b3a 100644 --- a/app/views/commits/_commit.html.haml +++ b/app/views/commits/_commit.html.haml @@ -1,17 +1,16 @@ %li.commit .browse_code_link_holder %p - %strong= link_to "Browse Code »", tree_project_ref_path(@project, commit.id), :class => "right" - = link_to project_commit_path(@project, :id => commit.id) do - %p - %code.left= commit.id.to_s[0..10] - %strong.cgray= commit.author_name - – - = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16 - %span.row_title= truncate(commit.safe_message, :length => 50) + %strong= link_to "Browse Code »", tree_project_ref_path(@project, commit.id), class: "right" + %p + = link_to commit.short_id(8), project_commit_path(@project, id: commit.id), class: "commit_short_id" + %strong.cgray= commit.author_name + – + = image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16 + = link_to_gfm truncate(commit.title, length: 50), project_commit_path(@project, id: commit.id), class: "row_title" - %span.committed_ago - = time_ago_in_words(commit.committed_date) - ago - + %span.committed_ago + = time_ago_in_words(commit.committed_date) + ago + diff --git a/app/views/commits/_commit_box.html.haml b/app/views/commits/_commit_box.html.haml index 8ccb3f1b72a..506f4e092a1 100644 --- a/app/views/commits/_commit_box.html.haml +++ b/app/views/commits/_commit_box.html.haml @@ -1,24 +1,24 @@ -.commit-box{class: @commit.parents.count > 1 ? "merge-commit" : ""} +.commit-box{class: @commit.parents_count > 1 ? "merge-commit" : ""} .commit-head .right - if @notes_count > 0 %span.btn.disabled.grouped %i.icon-comment = @notes_count - = link_to patch_project_commit_path(@project, @commit.id), :class => "btn small grouped" do + = link_to patch_project_commit_path(@project, @commit.id), class: "btn small grouped" do %i.icon-download-alt - Get Patch - = link_to tree_project_ref_path(@project, @commit.id), :class => "browse-button primary grouped" do + Get Patch + = link_to tree_project_ref_path(@project, @commit.id), class: "browse-button primary grouped" do %strong Browse Code » %h3.commit-title.page_title - = commit_msg_with_link_to_issues(@project, @commit.title) + = gfm @commit.title - if @commit.description.present? %pre.commit-description - = commit_msg_with_link_to_issues(@project, @commit.description) + = gfm @commit.description .commit-info .row .span4 - = image_tag gravatar_icon(@commit.author_email, 40), :class => "avatar" + = image_tag gravatar_icon(@commit.author_email, 40), class: "avatar" .author %strong= @commit.author_name authored diff --git a/app/views/commits/_diff_head.html.haml b/app/views/commits/_diff_head.html.haml index 11d6ca169d0..710e8857649 100644 --- a/app/views/commits/_diff_head.html.haml +++ b/app/views/commits/_diff_head.html.haml @@ -3,24 +3,24 @@ %li - if diff.deleted_file %span.removed_file - %a{:href => "##{diff.old_path}"} + %a{href: "##{diff.old_path}"} = diff.old_path = image_tag "diff_file_delete.png" - elsif diff.renamed_file %span.moved_file - %a{:href => "##{diff.new_path}"} + %a{href: "##{diff.new_path}"} = diff.old_path = "->" = diff.new_path = image_tag "diff_file_notice.png" - elsif diff.new_file %span.new_file - %a{:href => "##{diff.new_path}"} + %a{href: "##{diff.new_path}"} = diff.new_path = image_tag "diff_file_add.png" - else %span.edit_file - %a{:href => "##{diff.new_path}"} + %a{href: "##{diff.new_path}"} = diff.new_path = image_tag "diff_file_info.png" diff --git a/app/views/commits/_diffs.html.haml b/app/views/commits/_diffs.html.haml index d51561d90f8..b590d64c06e 100644 --- a/app/views/commits/_diffs.html.haml +++ b/app/views/commits/_diffs.html.haml @@ -5,12 +5,12 @@ %p To prevent performance issue we rejected diff information. %p But if you still want to see diff - = link_to "click this link", project_commit_path(@project, @commit.id, :force_show_diff => true), :class => "dark" + = link_to "click this link", project_commit_path(@project, @commit.id, force_show_diff: true), class: "dark" %p.cgray Showing #{pluralize(diffs.count, "changed file")} .file_stats - = render "commits/diff_head", :diffs => diffs + = render "commits/diff_head", diffs: diffs - unless @suppress_diff - diffs.each_with_index do |diff, i| @@ -22,26 +22,26 @@ .diff_file_header - if diff.deleted_file %i.icon-file - %span{:id => "#{diff.old_path}"}= diff.old_path + %span{id: "#{diff.old_path}"}= diff.old_path - else = link_to tree_file_project_ref_path(@project, @commit.id, diff.new_path) do %i.icon-file - %span{:id => "#{diff.new_path}"}= diff.new_path + %span{id: "#{diff.new_path}"}= diff.new_path %br/ .diff_file_content -# Skipp all non non-supported blobs - next unless file.respond_to?('text?') - if file.text? - = render "commits/text_file", :diff => diff, :index => i + = render "commits/text_file", diff: diff, index: i - elsif file.image? - if diff.renamed_file || diff.new_file || diff.deleted_file .diff_file_content_image - %img{:class => image_diff_class(diff), :src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} + %img{class: image_diff_class(diff), src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} - else - old_file = (@commit.prev_commit.tree / diff.old_path) .diff_file_content_image.img_compared - %img{:class => "diff_image_removed", :src => "data:#{file.mime_type};base64,#{Base64.encode64(old_file.data)}"} - %img{:class => "diff_image_added", :src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} + %img{class: "diff_image_removed", src: "data:#{file.mime_type};base64,#{Base64.encode64(old_file.data)}"} + %img{class: "diff_image_added", src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} - else %p.nothing_here_message No preview for this file type diff --git a/app/views/commits/_head.html.haml b/app/views/commits/_head.html.haml index 453ca4eac12..a211329f349 100644 --- a/app/views/commits/_head.html.haml +++ b/app/views/commits/_head.html.haml @@ -1,21 +1,21 @@ %ul.nav.nav-tabs %li - = form_tag switch_project_refs_path(@project), :method => :get, :class => "project-refs-form" do - = select_tag "ref", grouped_options_refs, :onchange => "$(this.form).trigger('submit');", :class => "project-refs-select" + = form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form" do + = select_tag "ref", grouped_options_refs, onchange: "$(this.form).trigger('submit');", class: "project-refs-select" = hidden_field_tag :destination, "commits" - %li{:class => "#{'active' if current_page?(project_commits_path(@project)) }"} + %li{class: "#{'active' if current_page?(project_commits_path(@project)) }"} = link_to project_commits_path(@project) do Commits - %li{:class => "#{'active' if current_page?(compare_project_commits_path(@project)) }"} + %li{class: "#{'active' if current_page?(compare_project_commits_path(@project)) }"} = link_to compare_project_commits_path(@project) do Compare - %li{:class => "#{branches_tab_class}"} + %li{class: "#{branches_tab_class}"} = link_to project_repository_path(@project) do Branches %span.badge= @project.repo.branch_count - %li{:class => "#{'active' if current_page?(tags_project_repository_path(@project)) }"} + %li{class: "#{'active' if current_page?(tags_project_repository_path(@project)) }"} = link_to tags_project_repository_path(@project) do Tags %span.badge= @project.repo.tag_count @@ -24,8 +24,8 @@ - if current_page?(project_commits_path(@project)) && current_user.private_token %li.right %span.rss-icon - = link_to project_commits_path(@project, :atom, { :private_token => current_user.private_token, :ref => @ref }), :title => "Feed" do - = image_tag "rss_ui.png", :title => "feed" + = link_to project_commits_path(@project, :atom, { private_token: current_user.private_token, ref: @ref }), title: "Feed" do + = image_tag "rss_ui.png", title: "feed" :javascript $(function(){ diff --git a/app/views/commits/_text_file.html.haml b/app/views/commits/_text_file.html.haml index cab066410b4..0f6210f2b5a 100644 --- a/app/views/commits/_text_file.html.haml +++ b/app/views/commits/_text_file.html.haml @@ -2,7 +2,7 @@ - if too_big %a.supp_diff_link Diff suppressed. Click to show -%table{:class => "#{'hide' if too_big}"} +%table{class: "#{'hide' if too_big}"} - each_diff_line(diff.diff.lines.to_a, index) do |line, type, line_code, line_new, line_old| %tr.line_holder - if type == "match" @@ -11,16 +11,16 @@ %td.line_content.matched= line - else %td.old_line - = link_to raw(type == "new" ? " " : line_old), "##{line_code}", :id => line_code + = link_to raw(type == "new" ? " " : line_old), "##{line_code}", id: line_code - if @comments_allowed - = link_to "", "#", :class => "line_note_link", "line_code" => line_code, :title => "Add note for this line" - %td.new_line= link_to raw(type == "old" ? " " : line_new) , "##{line_code}", :id => line_code - %td.line_content{:class => "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw "#{line} " + = link_to "", "#", class: "line_note_link", "line_code" => line_code, title: "Add note for this line" + %td.new_line= link_to raw(type == "old" ? " " : line_new) , "##{line_code}", id: line_code + %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw "#{line} " - if @comments_allowed - comments = @line_notes.select { |n| n.line_code == line_code }.sort_by(&:created_at).reverse - unless comments.empty? - comments.each_with_index do |note, i| - = render "notes/reply_button", :line_code => line_code if i.zero? - = render "notes/per_line_show", :note => note + = render "notes/reply_button", line_code: line_code if i.zero? + = render "notes/per_line_show", note: note - @line_notes.reject!{ |n| n == note } diff --git a/app/views/commits/compare.html.haml b/app/views/commits/compare.html.haml index 66ed8dad595..be915cd1038 100644 --- a/app/views/commits/compare.html.haml +++ b/app/views/commits/compare.html.haml @@ -14,22 +14,23 @@ %br - = form_tag compare_project_commits_path(@project), :method => :get do + = form_tag compare_project_commits_path(@project), method: :get do .clearfix - = text_field_tag :from, params[:from], :placeholder => "master", :class => "xlarge" + = text_field_tag :from, params[:from], placeholder: "master", class: "xlarge" = "..." - = text_field_tag :to, params[:to], :placeholder => "aa8b4ef", :class => "xlarge" + = text_field_tag :to, params[:to], placeholder: "aa8b4ef", class: "xlarge" .actions - = submit_tag "Compare", :class => "btn btn-primary" + = submit_tag "Compare", class: "btn btn-primary" - unless @commits.empty? - %h4 Commits (#{@commits.count}) - %ul.unstyled= render @commits + %div.ui-box + %h5.small Commits (#{@commits.count}) + %ul.unstyled= render @commits - unless @diffs.empty? %h4 Diff - = render "commits/diffs", :diffs => @diffs + = render "commits/diffs", diffs: @diffs :javascript $(function() { diff --git a/app/views/commits/index.atom.builder b/app/views/commits/index.atom.builder index 2a352dac1b7..cca704560e4 100644 --- a/app/views/commits/index.atom.builder +++ b/app/views/commits/index.atom.builder @@ -10,14 +10,14 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.entry do xml.id project_commit_url(@project, :id => commit.id) xml.link :href => project_commit_url(@project, :id => commit.id) - xml.title truncate(commit.safe_message, :length => 80) + xml.title truncate(commit.title, :length => 80) xml.updated commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ") xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(commit.author_email) xml.author do |author| xml.name commit.author_name xml.email commit.author_email end - xml.summary commit.safe_message + xml.summary gfm(commit.description) end end end diff --git a/app/views/commits/index.html.haml b/app/views/commits/index.html.haml index 385b4357e4e..11ffdb6afc3 100644 --- a/app/views/commits/index.html.haml +++ b/app/views/commits/index.html.haml @@ -9,12 +9,12 @@ %span.divider \/ %li - %a{:href => "#"}= params[:path].split("/").join(" / ") + %a{href: "#"}= params[:path].split("/").join(" / ") -%div{:id => dom_id(@project)} +%div{id: dom_id(@project)} #commits_list= render "commits" .clear -.loading{ :style => "display:none;"} +.loading{ style: "display:none;"} - if @commits.count == @limit :javascript diff --git a/app/views/commits/index.js.haml b/app/views/commits/index.js.haml index 39b7108c505..797bc14cc1b 100644 --- a/app/views/commits/index.js.haml +++ b/app/views/commits/index.js.haml @@ -1,3 +1,3 @@ :plain - CommitsList.append(#{@commits.count}, "#{escape_javascript(render(:partial => 'commits/commits'))}"); + CommitsList.append(#{@commits.count}, "#{escape_javascript(render(partial: 'commits/commits'))}"); diff --git a/app/views/commits/show.html.haml b/app/views/commits/show.html.haml index 7119bd04b9e..9a483aa2a9a 100644 --- a/app/views/commits/show.html.haml +++ b/app/views/commits/show.html.haml @@ -1,6 +1,6 @@ = render "commits/commit_box" -= render "commits/diffs", :diffs => @commit.diffs -= render "notes/notes", :tid => @commit.id, :tt => "commit" += render "commits/diffs", diffs: @commit.diffs += render "notes/notes", tid: @commit.id, tt: "commit" = render "notes/per_line_form" diff --git a/app/views/dashboard/index.html.haml b/app/views/dashboard/index.html.haml index b38544509b2..ba7d019cb63 100644 --- a/app/views/dashboard/index.html.haml +++ b/app/views/dashboard/index.html.haml @@ -1,20 +1,14 @@ - if @projects.any? .projects .activities.span8 - - if current_user.require_ssh_key? - .alert.alert-error.padded - %span - You wont be able to pull/push project code unless you - %strong - = link_to new_key_path, :class => "vlink" do - add new key - to your profile + = render 'shared/no_ssh' - if @events.any? - = render @events + .content_list= render @events - else %h4.nothing_here_message Projects activity will be displayed here + .loading.hide .side - = render "events/event_last_push", :event => @last_push + = render "events/event_last_push", event: @last_push .projects_box %h5 Projects @@ -22,23 +16,23 @@ (#{@projects.total_count}) - if current_user.can_create_project? %span.right - = link_to new_project_path, :class => "btn very_small info" do + = link_to new_project_path, class: "btn very_small info" do %i.icon-plus New Project - @projects.each do |project| - = link_to project_path(project), :class => dom_class(project) do + = link_to project_path(project), class: dom_class(project) do %h4 %span.ico.project - = truncate(project.name, :length => 25) + = truncate(project.name, length: 25) %span.right → - .bottom= paginate @projects, :theme => "gitlab" + .bottom= paginate @projects, theme: "gitlab" %hr %div %span.rss-icon - = link_to dashboard_path(:atom, { :private_token => current_user.private_token }) do - = image_tag "rss_ui.png", :title => "feed" + = link_to dashboard_path(:atom, { private_token: current_user.private_token }) do + = image_tag "rss_ui.png", title: "feed" %strong News Feed - else @@ -50,7 +44,11 @@ = current_user.projects_limit projects. Click on button below to add a new one .link_holder - = link_to new_project_path, :class => "btn primary" do + = link_to new_project_path, class: "btn primary" do New Project » - else If you will be added to project - it will be displayed here + + +:javascript + $(function(){ Pager.init(20); }); diff --git a/app/views/dashboard/index.js.haml b/app/views/dashboard/index.js.haml index aa038e75928..7e5a148e5ef 100644 --- a/app/views/dashboard/index.js.haml +++ b/app/views/dashboard/index.js.haml @@ -1,2 +1,2 @@ :plain - $(".projects .activities").append("#{escape_javascript(render(@events))}"); + Pager.append(#{@events.count}, "#{escape_javascript(render(@events))}"); diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml index ca87fc6f573..cc488d57e9e 100644 --- a/app/views/dashboard/issues.html.haml +++ b/app/views/dashboard/issues.html.haml @@ -8,12 +8,12 @@ - if @issues.any? - @issues.group_by(&:project).each do |group| %div.ui-box - - project = group[0] - %h5= project.name + - @project = group[0] + %h5= @project.name %ul.unstyled.issues_table - group[1].each do |issue| - = render(:partial => 'issues/show', :locals => {:issue => issue}) + = render(partial: 'issues/show', locals: {issue: issue}) %hr - = paginate @issues, :theme => "gitlab" + = paginate @issues, theme: "gitlab" - else %h3.nothing_here_message Nothing to show here diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml index ce3cd6b5959..23a7e7222d7 100644 --- a/app/views/dashboard/merge_requests.html.haml +++ b/app/views/dashboard/merge_requests.html.haml @@ -1,18 +1,18 @@ %h3.page_title Merge Requests - %small (authored or assigned to you) + %small (authored by or assigned to you) %small.right #{@merge_requests.total_count} merge requests %br - if @merge_requests.any? - @merge_requests.group_by(&:project).each do |group| %ul.unstyled.ui-box - - project = group[0] - %h5= project.name + - @project = group[0] + %h5= @project.name - group[1].each do |merge_request| - = render(:partial => 'merge_requests/merge_request', :locals => {:merge_request => merge_request}) + = render(partial: 'merge_requests/merge_request', locals: {merge_request: merge_request}) %hr - = paginate @merge_requests, :theme => "gitlab" + = paginate @merge_requests, theme: "gitlab" - else %h3.nothing_here_message Nothing to show here diff --git a/app/views/deploy_keys/_form.html.haml b/app/views/deploy_keys/_form.html.haml index 2aa57cdc59b..461f1f5d84a 100644 --- a/app/views/deploy_keys/_form.html.haml +++ b/app/views/deploy_keys/_form.html.haml @@ -1,5 +1,5 @@ %div - = form_for [@project, @key], :url => project_deploy_keys_path do |f| + = form_for [@project, @key], url: project_deploy_keys_path do |f| -if @key.errors.any? .alert-message.block-message.error %ul @@ -11,8 +11,8 @@ .input= f.text_field :title .clearfix = f.label :key - .input= f.text_area :key, :class => "xlarge" + .input= f.text_area :key, class: "xlarge" .actions - = f.submit 'Save', :class => "primary btn" - = link_to "Cancel", project_deploy_keys_path(@project), :class => "btn" + = f.submit 'Save', class: "primary btn" + = link_to "Cancel", project_deploy_keys_path(@project), class: "btn" diff --git a/app/views/deploy_keys/_show.html.haml b/app/views/deploy_keys/_show.html.haml index ff17b3cd66c..a5314ae92ad 100644 --- a/app/views/deploy_keys/_show.html.haml +++ b/app/views/deploy_keys/_show.html.haml @@ -1,6 +1,6 @@ %tr %td - %a{:href => project_deploy_key_path(key.project, key)} + %a{href: project_deploy_key_path(key.project, key)} %strong= key.title %td %span.update-author @@ -8,5 +8,5 @@ = time_ago_in_words(key.created_at) ago %td - = link_to 'Remove', project_deploy_key_path(key.project, key), :confirm => 'Are you sure?', :method => :delete, :class => "danger btn delete-key small right" + = link_to 'Remove', project_deploy_key_path(key.project, key), confirm: 'Are you sure?', method: :delete, class: "danger btn delete-key small right" diff --git a/app/views/deploy_keys/index.html.haml b/app/views/deploy_keys/index.html.haml index 19899de3cf6..0ee9d03b0f5 100644 --- a/app/views/deploy_keys/index.html.haml +++ b/app/views/deploy_keys/index.html.haml @@ -2,10 +2,10 @@ - if can? current_user, :admin_project, @project .alert-message.block-message Deploy keys allow read-only access to repository. - = link_to new_project_deploy_key_path(@project), :class => "btn small", :title => "New Deploy Key" do + = link_to new_project_deploy_key_path(@project), class: "btn small", title: "New Deploy Key" do Add Deploy Key - if @keys.any? %table - @keys.each do |key| - = render(:partial => 'show', :locals => {:key => key}) + = render(partial: 'show', locals: {key: key}) diff --git a/app/views/deploy_keys/show.html.haml b/app/views/deploy_keys/show.html.haml index 16c441bea73..b1e0dc5ce27 100644 --- a/app/views/deploy_keys/show.html.haml +++ b/app/views/deploy_keys/show.html.haml @@ -3,5 +3,5 @@ %hr %pre= @key.key .actions - = link_to 'Remove', project_deploy_key_path(@key.project, @key), :confirm => 'Are you sure?', :method => :delete, :class => "danger btn delete-key" + = link_to 'Remove', project_deploy_key_path(@key.project, @key), confirm: 'Are you sure?', method: :delete, class: "danger btn delete-key" .clear diff --git a/app/views/devise/passwords/edit.html.haml b/app/views/devise/passwords/edit.html.haml index dfd715ac13b..31d355673ab 100644 --- a/app/views/devise/passwords/edit.html.haml +++ b/app/views/devise/passwords/edit.html.haml @@ -1,12 +1,12 @@ -= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put, :class => "login-box" }) do |f| - = image_tag "login-logo.png", :width => "304", :height => "66", :class => "login-logo", :alt => "Login Logo" += form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put, class: "login-box" }) do |f| + = image_tag "login-logo.png", width: "304", height: "66", class: "login-logo", alt: "Login Logo" %h3 Change your password = devise_error_messages! = f.hidden_field :reset_password_token %div - = f.password_field :password, :class => "text top", :placeholder => "New password" + = f.password_field :password, class: "text top", placeholder: "New password" %div - = f.password_field :password_confirmation, :class => "text bottom", :placeholder => "Confirm new password" + = f.password_field :password_confirmation, class: "text bottom", placeholder: "Confirm new password" %div - = f.submit "Change my password", :class => "btn primary" - .right= render :partial => "devise/shared/links" + = f.submit "Change my password", class: "btn primary" + .right= render partial: "devise/shared/links" diff --git a/app/views/errors/access_denied.html.haml b/app/views/errors/access_denied.html.haml index 718663dbee1..3b60ed8b0ee 100644 --- a/app/views/errors/access_denied.html.haml +++ b/app/views/errors/access_denied.html.haml @@ -1,5 +1,4 @@ -.alert-message.block-message.error - %h3 Access Denied - %hr - %p Youre not allowed to access this page - %p Read more about project permissions #{link_to "here", help_permissions_path, :class => "vlink"} +%h1 Access Denied +%hr +%h2 You are not allowed to access this page. +%p Read more about project permissions #{link_to "here", help_permissions_path, class: "vlink"} diff --git a/app/views/errors/encoding.html.haml b/app/views/errors/encoding.html.haml index 0ffbadeb08d..4662437f2d2 100644 --- a/app/views/errors/encoding.html.haml +++ b/app/views/errors/encoding.html.haml @@ -2,5 +2,4 @@ %h3 Encoding Error %hr %p - Page cant be loaded cause of encoding error - + Page can't be loaded because of an encoding error. diff --git a/app/views/errors/git_not_found.html.haml b/app/views/errors/git_not_found.html.haml index b2399ac51dc..cd01ea1b0e6 100644 --- a/app/views/errors/git_not_found.html.haml +++ b/app/views/errors/git_not_found.html.haml @@ -1,9 +1,6 @@ -.alert-message.block-message.error - %h3 Git Resource Not found - %hr - %p - Application cant get access to some - %span.label branch - or - %span.label commit - in your repository. Maybe it was moved +%h1 404 +%hr +%h2 Git Resource Not found +%p + Application can't get access to some branch or commit in your repository. It + may have been moved. diff --git a/app/views/errors/gitolite.html.haml b/app/views/errors/gitolite.html.haml index 3691b309698..d5f51951d5e 100644 --- a/app/views/errors/gitolite.html.haml +++ b/app/views/errors/gitolite.html.haml @@ -1,19 +1,25 @@ -.alert-message.block-message.error - %h3 Gitolite Error - %hr - %h4 Application cant get access to your gitolite system. +%h1 Git Error +%hr +%h2 Gitlab was unable to access your Gitolite system. + +.git_error_tips + %h4 Tips for Administrator: %ol %li %p - Check 'config/gitlab.yml' for correct settings. + Check git logs in admin area %li %p - Make sure web server user has access to gitolite. - %a{:href => "https://github.com/gitlabhq/gitlabhq/wiki/Gitolite"} Setup tutorial + Check config/gitlab.yml for correct settings. %li %p - Try: + Diagnostic tool: + %pre + bundle exec rake gitlab:app:status RAILS_ENV=production + %li + %p + Permissions: %pre = preserve do sudo chmod -R 770 #{Gitlab.config.git_base_path} - sudo chown -R git:git #{Gitlab.config.git_base_path}
\ No newline at end of file + sudo chown -R git:git #{Gitlab.config.git_base_path} diff --git a/app/views/errors/not_found.html.haml b/app/views/errors/not_found.html.haml index 9b76a9bf908..a4e8d0204a9 100644 --- a/app/views/errors/not_found.html.haml +++ b/app/views/errors/not_found.html.haml @@ -1,5 +1,4 @@ -.alert-message.block-message.error - %h3 Not found - %hr - %p Resource you were looking for doesn't exist. - %P You may have mistyped the address or it was removed. +%h1 404 +%hr +%h2 The resource you were looking for doesn't exist. +%p You may have mistyped the address or the page may have moved. diff --git a/app/views/events/_commit.html.haml b/app/views/events/_commit.html.haml index 60112b508a8..1e5c00cb4f4 100644 --- a/app/views/events/_commit.html.haml +++ b/app/views/events/_commit.html.haml @@ -1,9 +1,8 @@ -%li.wll.commit - = link_to project_commit_path(project, :id => commit.id) do - %p - %code.left= commit.id.to_s[0..10] - %strong.cgray= commit.author_name - – - = image_tag gravatar_icon(commit.author_email), :class => "avatar", :width => 16 - %span.row_title= truncate(commit.safe_message, :length => 50) rescue "--broken encoding" - +- commit = CommitDecorator.decorate(commit) +%li.commit + %p + = link_to commit.short_id(8), project_commit_path(project, id: commit.id), class: "commit_short_id" + %strong.cdark= commit.author_name + – + = image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16 + = gfm truncate(commit.title, length: 50) rescue "--broken encoding" diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml index b3db83c26dd..d49f0382dea 100644 --- a/app/views/events/_event.html.haml +++ b/app/views/events/_event.html.haml @@ -1,13 +1,13 @@ - if event.allowed? - if event.issue? .event_feed - = render "events/event_issue", :event => event + = render "events/event_issue", event: event - elsif event.merge_request? .event_feed - = render "events/event_merge_request", :event => event + = render "events/event_merge_request", event: event - elsif event.push? .event_feed - = render "events/event_push", :event => event + = render "events/event_push", event: event diff --git a/app/views/events/_event_issue.html.haml b/app/views/events/_event_issue.html.haml index 4293be8204e..4d357b7f912 100644 --- a/app/views/events/_event_issue.html.haml +++ b/app/views/events/_event_issue.html.haml @@ -1,6 +1,6 @@ -= image_tag gravatar_icon(event.author_email), :class => "avatar" += image_tag gravatar_icon(event.author_email), class: "avatar" %strong #{event.author_name} -%span.event_label{:class => event.action_name}= event.action_name +%span.event_label{class: event.action_name}= event.action_name issue = link_to project_issue_path(event.project, event.issue) do %strong= truncate event.issue_title diff --git a/app/views/events/_event_last_push.html.haml b/app/views/events/_event_last_push.html.haml index 212ef817e60..4ef927495ae 100644 --- a/app/views/events/_event_last_push.html.haml +++ b/app/views/events/_event_last_push.html.haml @@ -1,13 +1,13 @@ - if show_last_push_widget?(event) .event_lp %div - = image_tag gravatar_icon(event.author_email), :class => "avatar" + = image_tag gravatar_icon(event.author_email), class: "avatar" %span Your pushed to = event.ref_type - = link_to project_commits_path(event.project, :ref => event.ref_name) do - %strong= truncate(event.ref_name, :length => 28) + = link_to project_commits_path(event.project, ref: event.ref_name) do + %strong= truncate(event.ref_name, length: 28) at %strong= link_to event.project.name, event.project - = link_to new_mr_path_from_push_event(event), :title => "New Merge Request", :class => "btn very_small primary" do + = link_to new_mr_path_from_push_event(event), title: "New Merge Request", class: "btn very_small primary" do Create Merge Request diff --git a/app/views/events/_event_merge_request.html.haml b/app/views/events/_event_merge_request.html.haml index 774921a7f2a..ceb39371a3a 100644 --- a/app/views/events/_event_merge_request.html.haml +++ b/app/views/events/_event_merge_request.html.haml @@ -1,8 +1,8 @@ - if event.action_name == "merged" .event_icon= image_tag "event_mr_merged.png" -= image_tag gravatar_icon(event.author_email), :class => "avatar" += image_tag gravatar_icon(event.author_email), class: "avatar" %strong #{event.author_name} -%span.event_label{:class => event.action_name}= event.action_name +%span.event_label{class: event.action_name}= event.action_name merge request = link_to project_merge_request_path(event.project, event.merge_request) do %strong= truncate event.merge_request_title diff --git a/app/views/events/_event_push.html.haml b/app/views/events/_event_push.html.haml index 59d8962bb16..0adcaf9d10e 100644 --- a/app/views/events/_event_push.html.haml +++ b/app/views/events/_event_push.html.haml @@ -1,10 +1,10 @@ %div .event_icon= image_tag "event_push.png" - = image_tag gravatar_icon(event.author_email), :class => "avatar" + = image_tag gravatar_icon(event.author_email), class: "avatar" %strong #{event.author_name} %span.event_label.pushed= event.push_action_name = event.ref_type - = link_to project_commits_path(event.project, :ref => event.ref_name) do + = link_to project_commits_path(event.project, ref: event.ref_name) do %strong= event.ref_name at %strong= link_to event.project.name, event.project @@ -14,17 +14,17 @@ - if event.push_with_commits? - if event.commits_count > 1 - = link_to compare_project_commits_path(event.project, :from => event.parent_commit.id, :to => event.last_commit.id) do + = link_to compare_project_commits_path(event.project, from: event.parent_commit.id, to: event.last_commit.id) do %strong #{event.parent_commit.id[0..7]}...#{event.last_commit.id[0..7]} - project = event.project %ul.unstyled.event_commits - if event.commits_count > 3 - event.commits[0...2].each do |commit| - = render "events/commit", :commit => commit, :project => project + = render "events/commit", commit: commit, project: project %li %br \... and #{event.commits_count - 2} more commits - else - event.commits.each do |commit| - = render "events/commit", :commit => commit, :project => project + = render "events/commit", commit: commit, project: project diff --git a/app/views/help/api.html.haml b/app/views/help/api.html.haml index 4964c1bbd87..4f7af193741 100644 --- a/app/views/help/api.html.haml +++ b/app/views/help/api.html.haml @@ -1,16 +1,20 @@ %h3 API .back_link - = link_to help_path do + = link_to help_path do ← to index %hr %ol - %li - %a{:href => "#README"} README - %li - %a{:href => "#projects"} Projects - %li - %a{:href => "#users"} Users + %li + %a{href: "#README"} README + %li + %a{href: "#projects"} Projects + %li + %a{href: "#snippets"} Snippets + %li + %a{href: "#users"} Users + %li + %a{href: "#issues"} Issues .file_holder#README .file_title @@ -32,6 +36,16 @@ %br +.file_holder#snippets + .file_title + %i.icon-file + Projects Snippets + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "api", "snippets.md")) + +%br + .file_holder#users .file_title %i.icon-file @@ -39,3 +53,13 @@ .file_content.wiki = preserve do = markdown File.read(Rails.root.join("doc", "api", "users.md")) + +%br + +.file_holder#issues + .file_title + %i.icon-file + Issues + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "api", "issues.md")) diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index b6c52712c4d..02549577282 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -24,4 +24,13 @@ %h5= link_to "Web Hooks", help_web_hooks_path %li + %h5= link_to "System Hooks", help_system_hooks_path + + %li %h5= link_to "API", help_api_path + + %li + %h5= link_to "Gitlab Markdown", help_markdown_path + + %li + %h5= link_to "SSH keys", help_ssh_path diff --git a/app/views/help/markdown.html.haml b/app/views/help/markdown.html.haml new file mode 100644 index 00000000000..8d6fb2a590f --- /dev/null +++ b/app/views/help/markdown.html.haml @@ -0,0 +1,25 @@ +- bash_lexer = Pygments::Lexer[:bash] +%h3.page_title Gitlab Markdown +.back_link + = link_to help_path do + ← to index +%hr + +%p.slead We extend Markdown with some GITLAB specific syntax. It allows you to link to: + +%ul + %li issues (#123) + %li merge request (!123) + %li commits (1234567) + %li team members (@foo) + %li snippets ($123) + +%p.slead in + +%ul + %li commit messages + %li notes/comments/wall posts + %li issues + %li merge requests + %li milestones + %li wiki pages diff --git a/app/views/help/permissions.html.haml b/app/views/help/permissions.html.haml index 860cfc8669c..f9287fa0996 100644 --- a/app/views/help/permissions.html.haml +++ b/app/views/help/permissions.html.haml @@ -1,6 +1,6 @@ -%h3 Permissions +%h3.page_title Permissions .back_link - = link_to help_path do + = link_to help_path do ← to index %hr @@ -38,7 +38,6 @@ %li Push to non-protected branches %li Remove non-protected branches %li Add tags - %li Create new merge request %li Write a wiki .ui-box.span3 @@ -55,7 +54,6 @@ %li Push to non-protected branches %li Remove non-protected branches %li Add tags - %li Create new merge request %li Write a wiki %li Add new team members %li Push to protected branches diff --git a/app/views/help/ssh.html.haml b/app/views/help/ssh.html.haml new file mode 100644 index 00000000000..6a5812040e7 --- /dev/null +++ b/app/views/help/ssh.html.haml @@ -0,0 +1,25 @@ +%h3.page_title SSH Keys +.back_link + = link_to help_path do + ← to index +%hr + +%p.slead + SSH key allows you to establish a secure connection between your computer and Gitlab + +%p.slead + To generate a new SSH key just open your terminal and use code below. + +%pre.dark + ssh-keygen -t rsa -C "#{current_user.email}" + + \# Creates a new ssh key using the provided email + \# Generating public/private rsa key pair... + +%p.slead + Next just use code below to dump your public key and add to GITLAB SSH Keys + +%pre.dark + cat ~/.ssh/id_rsa.pub + + \# ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6eNtGpNGwstc.... diff --git a/app/views/help/system_hooks.html.haml b/app/views/help/system_hooks.html.haml new file mode 100644 index 00000000000..9fc8cbabf17 --- /dev/null +++ b/app/views/help/system_hooks.html.haml @@ -0,0 +1,13 @@ +%h3 System hooks +.back_link + = link_to :back do + ← back +%hr + +%p.slead + Your Gitlab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member. + %br + System Hooks can be used for logging or change information in LDAP server. + %br +%h5 Hooks request example: += render "admin/hooks/data_ex" diff --git a/app/views/help/web_hooks.html.haml b/app/views/help/web_hooks.html.haml index 3acea62cf90..263eadf6583 100644 --- a/app/views/help/web_hooks.html.haml +++ b/app/views/help/web_hooks.html.haml @@ -1,11 +1,11 @@ -%h3 Web hooks +%h3.page_title Web hooks .back_link - = link_to help_path do + = link_to help_path do ← to index %hr -%p.slead - Every Gitlab project can trigger a web server whenever the repo is pushed to. +%p.slead + Every Gitlab project can trigger a web server whenever the repo is pushed to. %br Web Hooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server. %br diff --git a/app/views/help/workflow.html.haml b/app/views/help/workflow.html.haml index 7db8133b7f3..a3fe3b01d46 100644 --- a/app/views/help/workflow.html.haml +++ b/app/views/help/workflow.html.haml @@ -1,7 +1,6 @@ -- bash_lexer = Pygments::Lexer[:bash] -%h3 Workflow +%h3.page_title Workflow .back_link - = link_to help_path do + = link_to help_path do ← to index %hr @@ -9,25 +8,25 @@ %li %p Clone project .bash - %pre + %pre.dark git clone git@example.com:project-name.git %li %p Create branch with your feature .bash - %pre + %pre.dark git checkout -b $feature_name %li %p Write code. Commit changes .bash - %pre + %pre.dark git commit -am "My feature is ready" %li %p Push your branch to gitlabhq .bash - %pre + %pre.dark git push origin $feature_name %li diff --git a/app/views/hooks/index.html.haml b/app/views/hooks/index.html.haml index 15699fc4390..3d2a381e746 100644 --- a/app/views/hooks/index.html.haml +++ b/app/views/hooks/index.html.haml @@ -6,9 +6,9 @@ Post receive hooks for binding events when someone push to repository. %br Read more about web hooks - %strong #{link_to "here", help_web_hooks_path, :class => "vlink"} + %strong #{link_to "here", help_web_hooks_path, class: "vlink"} -= form_for [@project, @hook], :as => :hook, :url => project_hooks_path(@project) do |f| += form_for [@project, @hook], as: :hook, url: project_hooks_path(@project), html: { class: 'form-inline' } do |f| -if @hook.errors.any? .alert-message.block-message.error - @hook.errors.full_messages.each do |msg| @@ -16,9 +16,9 @@ .clearfix = f.label :url, "URL:" .input - = f.text_field :url, :class => "text_field xxlarge" + = f.text_field :url, class: "text_field xxlarge" - = f.submit "Add Web Hook", :class => "btn primary" + = f.submit "Add Web Hook", class: "btn primary" %hr -if @hooks.any? @@ -36,7 +36,7 @@ %td = link_to project_hook_path(@project, hook) do %strong= hook.url - = link_to 'Test Hook', test_project_hook_path(@project, hook), :class => "btn small right" + = link_to 'Test Hook', test_project_hook_path(@project, hook), class: "btn small right" %td POST %td - = link_to 'Remove', project_hook_path(@project, hook), :confirm => 'Are you sure?', :method => :delete, :class => "danger btn small right" + = link_to 'Remove', project_hook_path(@project, hook), confirm: 'Are you sure?', method: :delete, class: "danger btn small right" diff --git a/app/views/issues/_form.html.haml b/app/views/issues/_form.html.haml index 4f6f8396661..1b67eabd5a5 100644 --- a/app/views/issues/_form.html.haml +++ b/app/views/issues/_form.html.haml @@ -1,6 +1,6 @@ %div.issue-form-holder - %h3= @issue.new_record? ? "New Issue" : "Edit Issue ##{@issue.id}" - = form_for [@project, @issue], :remote => request.xhr? do |f| + %h3.page_title= @issue.new_record? ? "New Issue" : "Edit Issue ##{@issue.id}" + = form_for [@project, @issue], remote: request.xhr? do |f| -if @issue.errors.any? .alert-message.block-message.error %ul @@ -9,48 +9,48 @@ .issue_form_box .issue_title .clearfix - = f.label :title do + = f.label :title do %strong= "Subject *" .input - = f.text_field :title, :maxlength => 255, :class => "xxlarge" + = f.text_field :title, maxlength: 255, class: "xxlarge" .issue_middle_block .issue_assignee - = f.label :assignee_id do + = f.label :assignee_id do %i.icon-user Assign to - .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select a user" }) + .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" }) .issue_milestone - = f.label :milestone_id do + = f.label :milestone_id do %i.icon-time Milestone - .input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { :include_blank => "Select milestone" }) + .input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }) .issue_description .clearfix - = f.label :label_list do - %i.icon-tag + = f.label :label_list do + %i.icon-tag Labels .input - = f.text_field :label_list, :maxlength => 2000, :class => "xxlarge" + = f.text_field :label_list, maxlength: 2000, class: "xxlarge" %p.hint Separate with comma. .clearfix = f.label :description, "Details" .input - = f.text_area :description, :maxlength => 2000, :class => "xxlarge", :rows => 14 + = f.text_area :description, maxlength: 2000, class: "xxlarge", rows: 14 %p.hint Markdown is enabled. .actions - if @issue.new_record? - = f.submit 'Submit new issue', :class => "primary btn" + = f.submit 'Submit new issue', class: "primary btn" -else - = f.submit 'Save changes', :class => "primary btn" + = f.submit 'Save changes', class: "primary btn" - if request.xhr? - = link_to "Cancel", "#back", :onclick => "backToIssues();", :class => "btn" + = link_to "Cancel", "#back", onclick: "backToIssues();", class: "btn" - else - if @issue.new_record? - = link_to "Cancel", project_issues_path(@project), :class => "btn" + = link_to "Cancel", project_issues_path(@project), class: "btn" - else - = link_to "Cancel", project_issue_path(@project, @issue), :class => "btn" + = link_to "Cancel", project_issue_path(@project, @issue), class: "btn" diff --git a/app/views/issues/_head.html.haml b/app/views/issues/_head.html.haml index 701b0625852..8ebe3e057bc 100644 --- a/app/views/issues/_head.html.haml +++ b/app/views/issues/_head.html.haml @@ -1,11 +1,14 @@ %ul.nav.nav-tabs - %li{:class => "#{'active' if current_page?(project_issues_path(@project))}"} - = link_to project_issues_path(@project), :class => "tab" do + %li{class: "#{'active' if current_page?(project_issues_path(@project))}"} + = link_to project_issues_path(@project), class: "tab" do Browse Issues - %li{:class => "#{'active' if current_page?(project_milestones_path(@project))}"} - = link_to project_milestones_path(@project), :class => "tab" do + %li{class: "#{'active' if current_page?(project_milestones_path(@project))}"} + = link_to project_milestones_path(@project), class: "tab" do Milestones + %li{class: "#{'active' if current_page?(project_labels_path(@project))}"} + = link_to project_labels_path(@project), class: "tab" do + Labels %li.right %span.rss-icon - = link_to project_issues_path(@project, :atom, { :private_token => current_user.private_token }) do - = image_tag "rss_ui.png", :title => "feed" + = link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do + = image_tag "rss_ui.png", title: "feed" diff --git a/app/views/issues/_issues.html.haml b/app/views/issues/_issues.html.haml index 17141cc453c..f82ae8bde58 100644 --- a/app/views/issues/_issues.html.haml +++ b/app/views/issues/_issues.html.haml @@ -1,10 +1,10 @@ - @issues.each do |issue| - = render(:partial => 'issues/show', :locals => {:issue => issue}) + = render(partial: 'issues/show', locals: {issue: issue}) - if @issues.present? %li.bottom .row - .span7= paginate @issues, :remote => true, :theme => "gitlab" + .span7= paginate @issues, remote: true, theme: "gitlab" .span3.right %span.cgray.right %span.issue_counter #{@issues.total_count} @@ -12,3 +12,4 @@ - else %li %h4.nothing_here_message Nothing to show here + diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_show.html.haml index e12c3c1a99c..8500cd40a6e 100644 --- a/app/views/issues/_show.html.haml +++ b/app/views/issues/_show.html.haml @@ -1,6 +1,7 @@ -%li.wll{ :id => dom_id(issue), :class => issue_css_classes(issue), :url => project_issue_path(issue.project, issue) } - .list_legend - .icon +%li.wll{ id: dom_id(issue), class: issue_css_classes(issue), url: project_issue_path(issue.project, issue) } + - if controller.controller_name == 'issues' + .issue_check + = check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue", disabled: !can?(current_user, :modify_issue, issue) .right - issue.labels.each do |label| %span.label.label-issue.grouped @@ -12,20 +13,19 @@ = issue.notes.count - if can? current_user, :modify_issue, issue - if issue.closed - = link_to 'Reopen', project_issue_path(issue.project, issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "btn small grouped reopen_issue", :remote => true + = link_to 'Reopen', project_issue_path(issue.project, issue, issue: {closed: false }, status_only: true), method: :put, class: "btn small grouped reopen_issue", remote: true - else - = link_to 'Resolve', project_issue_path(issue.project, issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "success btn small grouped close_issue", :remote => true - = link_to edit_project_issue_path(issue.project, issue), :class => "btn small edit-issue-link", :remote => true do + = link_to 'Resolve', project_issue_path(issue.project, issue, issue: {closed: true }, status_only: true), method: :put, class: "success btn small grouped close_issue", remote: true + = link_to edit_project_issue_path(issue.project, issue), class: "btn small edit-issue-link", remote: true do %i.icon-edit Edit - if issue.assignee - = image_tag gravatar_icon(issue.assignee_email), :class => "avatar" + = image_tag gravatar_icon(issue.assignee_email), class: "avatar" - else - = image_tag "no_avatar.png", :class => "avatar" + = image_tag "no_avatar.png", class: "avatar" - = link_to project_issue_path(issue.project, issue) do - %p.row_title= truncate(issue.title, :length => 100) + %p= link_to_gfm truncate(issue.title, length: 100), project_issue_path(issue.project, issue), class: "row_title" %span.update-author %small.cdark= "##{issue.id}" @@ -35,4 +35,4 @@ - if issue.upvotes > 0 - %span.badge.badge-success= "+#{issue.upvotes}"
\ No newline at end of file + %span.badge.badge-success= "+#{issue.upvotes}" diff --git a/app/views/issues/create.js.haml b/app/views/issues/create.js.haml index abf3f6b858b..d90cbf0d30c 100644 --- a/app/views/issues/create.js.haml +++ b/app/views/issues/create.js.haml @@ -1,7 +1,7 @@ - if @issue.valid? :plain switchFromNewIssue(); - $("#issues-table").prepend("#{escape_javascript(render(:partial => 'show', :locals => {:issue => @issue}))}"); + $("#issues-table").prepend("#{escape_javascript(render(partial: 'show', locals: {issue: @issue}))}"); $.ajax({type: "GET", url: location.href, dataType: "script"}); - else :plain diff --git a/app/views/issues/index.html.haml b/app/views/issues/index.html.haml index fb8b9f8ee8e..a6836fd4fd1 100644 --- a/app/views/issues/index.html.haml +++ b/app/views/issues/index.html.haml @@ -6,43 +6,60 @@ .right .span5 - if can? current_user, :write_issue, @project - = link_to new_project_issue_path(@project), :class => "right btn small", :title => "New Issue", :remote => true do + = link_to new_project_issue_path(@project), class: "right btn small", title: "New Issue", remote: true do + %i.icon-plus New Issue - = form_tag search_project_issues_path(@project), :method => :get, :remote => true, :id => "issue_search_form", :class => :right do - = hidden_field_tag :project_id, @project.id, { :id => 'project_id' } + = form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do + = hidden_field_tag :project_id, @project.id, { id: 'project_id' } = hidden_field_tag :status, params[:f] - = search_field_tag :issue_search, nil, { :placeholder => 'Search', :class => 'issue_search span3 right neib' } + = search_field_tag :issue_search, nil, { placeholder: 'Search', class: 'issue_search span3 right neib' } .clearfix + %div#issues-table-holder.ui-box .title - .left - %ul.nav.nav-pills.left - %li{:class => ("active" if (params[:f] == issues_filter[:open] || !params[:f]))} - = link_to project_issues_path(@project, :f => issues_filter[:open], :milestone_id => params[:milestone_id]) do - Open - %li{:class => ("active" if params[:f] == issues_filter[:closed])} - = link_to project_issues_path(@project, :f => issues_filter[:closed], :milestone_id => params[:milestone_id]) do - Closed - %li{:class => ("active" if params[:f] == issues_filter[:to_me])} - = link_to project_issues_path(@project, :f => issues_filter[:to_me], :milestone_id => params[:milestone_id]) do - To Me - %li{:class => ("active" if params[:f] == issues_filter[:all])} - = link_to project_issues_path(@project, :f => issues_filter[:all], :milestone_id => params[:milestone_id]) do - All - - .right - = form_tag project_issues_path(@project), :method => :get, :class => :right do - = select_tag(:label_name, options_for_select(issue_tags, params[:label_name]), :prompt => "Labels") - = select_tag(:assignee_id, options_from_collection_for_select(@project.users.all, "id", "name", params[:assignee_id]), :prompt => "Assignee") - = select_tag(:milestone_id, options_from_collection_for_select(@project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), :prompt => "Milestone") - = hidden_field_tag :f, params[:f] - .clearfix - + = check_box_tag "check_all_issues", nil, false, class: "check_all_issues left" + + + .issues_bulk_update.hide + = form_tag bulk_update_project_issues_path(@project), method: :post do + %span.update_issues_text Update selected issues with + .left + = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status") + = select_tag('update[assignee_id]', options_from_collection_for_select(@project.users.all, "id", "name", params[:assignee_id]), prompt: "Assignee") + = select_tag('update[milestone_id]', options_from_collection_for_select(@project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), prompt: "Milestone") + = hidden_field_tag 'update[issues_ids]', [] + = hidden_field_tag :f, params[:f] + = button_tag "Save", class: "btn update_selected_issues" + .issues_filters + .left + %ul.nav.nav-pills.left + %li{class: ("active" if (params[:f] == issues_filter[:open] || !params[:f]))} + = link_to project_issues_path(@project, f: issues_filter[:open], milestone_id: params[:milestone_id]) do + Open + %li{class: ("active" if params[:f] == issues_filter[:closed])} + = link_to project_issues_path(@project, f: issues_filter[:closed], milestone_id: params[:milestone_id]) do + Closed + %li{class: ("active" if params[:f] == issues_filter[:to_me])} + = link_to project_issues_path(@project, f: issues_filter[:to_me], milestone_id: params[:milestone_id]) do + To Me + %li{class: ("active" if params[:f] == issues_filter[:all])} + = link_to project_issues_path(@project, f: issues_filter[:all], milestone_id: params[:milestone_id]) do + All + + .right + = form_tag project_issues_path(@project), method: :get, class: :right do + = select_tag(:label_name, options_for_select(issue_tags, params[:label_name]), prompt: "Labels") + = select_tag(:assignee_id, options_from_collection_for_select([unassigned_filter] + @project.users.all, "id", "name", params[:assignee_id]), prompt: "Assignee") + = select_tag(:milestone_id, options_from_collection_for_select([unassigned_filter] + @project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), prompt: "Milestone") + = hidden_field_tag :f, params[:f] + .clearfix + %ul#issues-table.unstyled.issues_table = render "issues" + :javascript $(function(){ issuesPage(); - })
\ No newline at end of file + }) diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index 8ffc9c2b662..dce8cf6a59d 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -8,11 +8,11 @@ %span.right - if can?(current_user, :admin_project, @project) || @issue.author == current_user - if @issue.closed - = link_to 'Reopen', project_issue_path(@project, @issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "btn small" + = link_to 'Reopen', project_issue_path(@project, @issue, issue: {closed: false }, status_only: true), method: :put, class: "btn small" - else - = link_to 'Close', project_issue_path(@project, @issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "btn small", :title => "Close Issue" + = link_to 'Close', project_issue_path(@project, @issue, issue: {closed: true }, status_only: true), method: :put, class: "btn small", title: "Close Issue" - if can?(current_user, :admin_project, @project) || @issue.author == current_user - = link_to edit_project_issue_path(@project, @issue), :class => "btn small" do + = link_to edit_project_issue_path(@project, @issue), class: "btn small" do %i.icon-edit Edit @@ -31,24 +31,22 @@ .alert-message.error.status_info Closed - else .alert-message.success.status_info Open - = @issue.title + = gfm @issue.title .middle_box_content %cite.cgray Created by - = image_tag gravatar_icon(@issue.author_email), :width => 16, :class => "lil_av" + = image_tag gravatar_icon(@issue.author_email), width: 16, class: "lil_av" %strong.author= link_to_issue_author(@issue) - if @issue.assignee %cite.cgray and currently assigned to - = image_tag gravatar_icon(@issue.assignee_email), :width => 16, :class => "lil_av" + = image_tag gravatar_icon(@issue.assignee_email), width: 16, class: "lil_av" %strong.author= link_to_issue_assignee(@issue) - if @issue.milestone - milestone = @issue.milestone %cite.cgray and attached to milestone - = link_to project_milestone_path(milestone.project, milestone) do - %strong - = truncate(milestone.title, :length => 20) + %strong= link_to_gfm truncate(milestone.title, length: 20), project_milestone_path(milestone.project, milestone) .right - @issue.labels.each do |label| @@ -63,4 +61,4 @@ = markdown @issue.description -.issue_notes#notes= render "notes/notes", :tid => @issue.id, :tt => "issue" +.issue_notes#notes= render "notes/notes", tid: @issue.id, tt: "issue" diff --git a/app/views/kaminari/admin/_first_page.html.haml b/app/views/kaminari/admin/_first_page.html.haml index fee8112f6af..41c9c0b3af6 100644 --- a/app/views/kaminari/admin/_first_page.html.haml +++ b/app/views/kaminari/admin/_first_page.html.haml @@ -6,4 +6,4 @@ -# per_page: number of items to fetch per page -# remote: data-remote %span.first - = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, :remote => remote + = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, remote: remote diff --git a/app/views/kaminari/admin/_last_page.html.haml b/app/views/kaminari/admin/_last_page.html.haml index 6e41d232b51..b03a206224c 100644 --- a/app/views/kaminari/admin/_last_page.html.haml +++ b/app/views/kaminari/admin/_last_page.html.haml @@ -6,4 +6,4 @@ -# per_page: number of items to fetch per page -# remote: data-remote %span.last - = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {:remote => remote} + = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {remote: remote} diff --git a/app/views/kaminari/admin/_next_page.html.haml b/app/views/kaminari/admin/_next_page.html.haml index 76f40e72373..00c5f0b6f4e 100644 --- a/app/views/kaminari/admin/_next_page.html.haml +++ b/app/views/kaminari/admin/_next_page.html.haml @@ -6,4 +6,4 @@ -# per_page: number of items to fetch per page -# remote: data-remote %li.next - = link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, :rel => 'next', :remote => remote + = link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, rel: 'next', remote: remote diff --git a/app/views/kaminari/admin/_page.html.haml b/app/views/kaminari/admin/_page.html.haml index 5966812934f..a52d883b9a8 100644 --- a/app/views/kaminari/admin/_page.html.haml +++ b/app/views/kaminari/admin/_page.html.haml @@ -6,5 +6,5 @@ -# num_pages: total number of pages -# per_page: number of items to fetch per page -# remote: data-remote -%li{:class => "page#{' active' if page.current?}"} - = link_to page, url, {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil} +%li{class: "page#{' active' if page.current?}"} + = link_to page, url, {remote: remote, rel: page.next? ? 'next' : page.prev? ? 'prev' : nil} diff --git a/app/views/kaminari/admin/_prev_page.html.haml b/app/views/kaminari/admin/_prev_page.html.haml index cef885ee0af..f673abdb3ae 100644 --- a/app/views/kaminari/admin/_prev_page.html.haml +++ b/app/views/kaminari/admin/_prev_page.html.haml @@ -5,5 +5,5 @@ -# num_pages: total number of pages -# per_page: number of items to fetch per page -# remote: data-remote -%li{:class => "prev" } - = link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote +%li{class: "prev" } + = link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, rel: 'prev', remote: remote diff --git a/app/views/kaminari/gitlab/_first_page.html.haml b/app/views/kaminari/gitlab/_first_page.html.haml index fee8112f6af..41c9c0b3af6 100644 --- a/app/views/kaminari/gitlab/_first_page.html.haml +++ b/app/views/kaminari/gitlab/_first_page.html.haml @@ -6,4 +6,4 @@ -# per_page: number of items to fetch per page -# remote: data-remote %span.first - = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, :remote => remote + = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, remote: remote diff --git a/app/views/kaminari/gitlab/_last_page.html.haml b/app/views/kaminari/gitlab/_last_page.html.haml index 6e41d232b51..b03a206224c 100644 --- a/app/views/kaminari/gitlab/_last_page.html.haml +++ b/app/views/kaminari/gitlab/_last_page.html.haml @@ -6,4 +6,4 @@ -# per_page: number of items to fetch per page -# remote: data-remote %span.last - = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {:remote => remote} + = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {remote: remote} diff --git a/app/views/kaminari/gitlab/_next_page.html.haml b/app/views/kaminari/gitlab/_next_page.html.haml index e87ab4e0534..296cceb080b 100644 --- a/app/views/kaminari/gitlab/_next_page.html.haml +++ b/app/views/kaminari/gitlab/_next_page.html.haml @@ -6,4 +6,4 @@ -# per_page: number of items to fetch per page -# remote: data-remote %span.next - = link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, :rel => 'next', :remote => remote + = link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, rel: 'next', remote: remote diff --git a/app/views/kaminari/gitlab/_page.html.haml b/app/views/kaminari/gitlab/_page.html.haml index 528bba8f116..19456dcc058 100644 --- a/app/views/kaminari/gitlab/_page.html.haml +++ b/app/views/kaminari/gitlab/_page.html.haml @@ -6,5 +6,5 @@ -# num_pages: total number of pages -# per_page: number of items to fetch per page -# remote: data-remote -%span{:class => "page#{' current' if page.current?}"} - = link_to_unless page.current?, page, url, {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil} +%span{class: "page#{' current' if page.current?}"} + = link_to_unless page.current?, page, url, {remote: remote, rel: page.next? ? 'next' : page.prev? ? 'prev' : nil} diff --git a/app/views/kaminari/gitlab/_prev_page.html.haml b/app/views/kaminari/gitlab/_prev_page.html.haml index 13f0d8adec5..5c2061690ac 100644 --- a/app/views/kaminari/gitlab/_prev_page.html.haml +++ b/app/views/kaminari/gitlab/_prev_page.html.haml @@ -6,4 +6,4 @@ -# per_page: number of items to fetch per page -# remote: data-remote %span.prev - = link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote + = link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, rel: 'prev', remote: remote diff --git a/app/views/keys/_form.html.haml b/app/views/keys/_form.html.haml index c25e8d073b8..9c6e229bf49 100644 --- a/app/views/keys/_form.html.haml +++ b/app/views/keys/_form.html.haml @@ -11,8 +11,14 @@ .input= f.text_field :title .clearfix = f.label :key - .input= f.text_area :key, :class => [:xxlarge, :thin_area] + .input + = f.text_area :key, class: [:xxlarge, :thin_area] + %p.hint + Paste your public key here. Read more about how generate it + = link_to "here", help_ssh_path + + .actions - = f.submit 'Save', :class => "primary btn" - = link_to "Cancel", keys_path, :class => "btn" + = f.submit 'Save', class: "primary btn" + = link_to "Cancel", keys_path, class: "btn" diff --git a/app/views/keys/_show.html.haml b/app/views/keys/_show.html.haml index 7035e609f2c..a0af8eea44c 100644 --- a/app/views/keys/_show.html.haml +++ b/app/views/keys/_show.html.haml @@ -9,5 +9,5 @@ = time_ago_in_words(key.created_at) ago %td - = link_to 'Remove', key, :confirm => 'Are you sure?', :method => :delete, :class => "btn small danger delete-key right" + = link_to 'Remove', key, confirm: 'Are you sure?', method: :delete, class: "btn small danger delete-key right" diff --git a/app/views/keys/create.js.haml b/app/views/keys/create.js.haml index b0d7f528be1..1dccf6fdb91 100644 --- a/app/views/keys/create.js.haml +++ b/app/views/keys/create.js.haml @@ -1,7 +1,7 @@ - if @key.valid? :plain $("#new_key_dialog").dialog("close"); - $("#keys-table .data").append("#{escape_javascript(render(:partial => 'show', :locals => {:key => @key}))}"); + $("#keys-table .data").append("#{escape_javascript(render(partial: 'show', locals: {key: @key}))}"); $("#no_ssh_key_defined").hide(); - else :plain diff --git a/app/views/keys/index.html.haml b/app/views/keys/index.html.haml index 35cda178242..04e9e4cbc33 100644 --- a/app/views/keys/index.html.haml +++ b/app/views/keys/index.html.haml @@ -1,6 +1,6 @@ %h3.page_title SSH Keys - = link_to "Add new", new_key_path, :class => "btn small right" + = link_to "Add new", new_key_path, class: "btn small right" %hr %p.slead @@ -14,9 +14,9 @@ %th Added %th - @keys.each do |key| - = render(:partial => 'show', :locals => {:key => key}) + = render(partial: 'show', locals: {key: key}) - if @keys.blank? %tr - %td{:colspan => 3} + %td{colspan: 3} %h3.nothing_here_message There are no SSH keys with access to your account. diff --git a/app/views/keys/new.html.haml b/app/views/keys/new.html.haml index 02e782b9f85..fff3805890e 100644 --- a/app/views/keys/new.html.haml +++ b/app/views/keys/new.html.haml @@ -1,4 +1,4 @@ -%h3.page_title New key +%h3.page_title Add an SSH Key %hr = render 'form' diff --git a/app/views/keys/show.html.haml b/app/views/keys/show.html.haml index 79f51257fd9..ffd52b96e5a 100644 --- a/app/views/keys/show.html.haml +++ b/app/views/keys/show.html.haml @@ -11,4 +11,4 @@ %pre= @key.key .actions - = link_to 'Remove', @key, :confirm => 'Are you sure?', :method => :delete, :class => "btn danger delete-key" + = link_to 'Remove', @key, confirm: 'Are you sure?', method: :delete, class: "btn danger delete-key" diff --git a/app/views/labels/_label.html.haml b/app/views/labels/_label.html.haml new file mode 100644 index 00000000000..32158c20adc --- /dev/null +++ b/app/views/labels/_label.html.haml @@ -0,0 +1,4 @@ +%li.wll + %strong= label.name + .right + %span= pluralize label.count, 'issue' diff --git a/app/views/labels/index.html.haml b/app/views/labels/index.html.haml new file mode 100644 index 00000000000..4e41d375d6a --- /dev/null +++ b/app/views/labels/index.html.haml @@ -0,0 +1,14 @@ += render "issues/head" + +%h3.page_title + Labels +%br +%div.ui-box + %ul.unstyled.labels-table + - @labels.each do |label| + = render 'label', label: label + + - unless @labels.present? + %li + %h3.nothing_here_message Nothing to show here + diff --git a/app/views/layouts/_app_menu.html.haml b/app/views/layouts/_app_menu.html.haml index 6575ee99168..025314891f8 100644 --- a/app/views/layouts/_app_menu.html.haml +++ b/app/views/layouts/_app_menu.html.haml @@ -1,19 +1,19 @@ %ul.main_menu - %li.home{:class => tab_class(:root)} - = link_to "Home", root_path, :title => "Home" + %li.home{class: tab_class(:root)} + = link_to "Home", root_path, title: "Home" - %li{:class => tab_class(:dash_issues)} + %li{class: tab_class(:dash_issues)} = link_to dashboard_issues_path do Issues %span.count= current_user.assigned_issues.opened.count - %li{:class => tab_class(:dash_mr)} + %li{class: tab_class(:dash_mr)} = link_to dashboard_merge_requests_path do Merge Requests %span.count= current_user.cared_merge_requests.count - %li{:class => tab_class(:search)} + %li{class: tab_class(:search)} = link_to "Search", search_path - %li{:class => tab_class(:help)} + %li{class: tab_class(:help)} = link_to "Help", help_path diff --git a/app/views/layouts/_flash.html.haml b/app/views/layouts/_flash.html.haml index 2e40f0a6281..86564ad7110 100644 --- a/app/views/layouts/_flash.html.haml +++ b/app/views/layouts/_flash.html.haml @@ -1,6 +1,6 @@ - if alert || notice - text = alert || notice - %div{:style => "display:none", :id => "flash_container"} + %div{style: "display:none", id: "flash_container"} %center %h4= text :javascript diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index e609557b17a..c076a3a1b45 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -1,18 +1,17 @@ %head - %meta{:charset => "utf-8"} + %meta{charset: "utf-8"} %title GitLab = " > #{@project.name}" if @project && !@project.new_record? = favicon_link_tag 'favicon.ico' = stylesheet_link_tag "application" = javascript_include_tag "application" - -# Atom feed - if controller_name == 'projects' && action_name == 'index' - = auto_discovery_link_tag :atom, projects_url(:atom, :private_token => current_user.private_token), :title => "Dashboard feed" + = auto_discovery_link_tag :atom, projects_url(:atom, private_token: current_user.private_token), title: "Dashboard feed" - if @project && !@project.new_record? - if current_page?(tree_project_ref_path(@project, @project.root_ref)) || current_page?(project_commits_path(@project)) - = auto_discovery_link_tag(:atom, project_commits_url(@project, :atom, :ref => @ref, :private_token => current_user.private_token), :title => "Recent commits to #{@project.name}:#{@ref}") + = auto_discovery_link_tag(:atom, project_commits_url(@project, :atom, ref: @ref, private_token: current_user.private_token), title: "Recent commits to #{@project.name}:#{@ref}") - if request.path == project_issues_path(@project) - = auto_discovery_link_tag(:atom, project_issues_url(@project, :atom, :private_token => current_user.private_token), :title => "#{@project.name} issues") + = auto_discovery_link_tag(:atom, project_issues_url(@project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues") = csrf_meta_tags diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml index 9e019021c89..d6247d36b0d 100644 --- a/app/views/layouts/_head_panel.html.haml +++ b/app/views/layouts/_head_panel.html.haml @@ -3,30 +3,30 @@ .container .top_panel_content %div.app_logo - = link_to root_path, :class => "home", :title => "Home" do + = link_to root_path, class: "home", title: "Home" do %h1 GITLAB %span.separator %h1.project_name= title .search - = form_tag search_path, :method => :get do |f| - = text_field_tag "search", nil, :placeholder => "Search", :class => "search-input" + = form_tag search_path, method: :get do |f| + = text_field_tag "search", nil, placeholder: "Search", class: "search-input" .fbtn - if current_user.is_admin? - = link_to admin_root_path, :class => "btn small", :title => "Admin area" do + = link_to admin_root_path, class: "btn small", title: "Admin area" do %i.icon-cog Admin - if current_user.can_create_project? - = link_to new_project_path, :class => "btn small", :title => "Create New Project" do + = link_to new_project_path, class: "btn small", title: "Create New Project" do %i.icon-plus Project .account-box - = link_to profile_path, :class => "pic" do + = link_to profile_path, class: "pic" do = image_tag gravatar_icon(current_user.email) .account-links - = link_to profile_path, :class => "username" do + = link_to profile_path, class: "username" do My profile - = link_to 'Logout', destroy_user_session_path, :class => "logout", :method => :delete + = link_to 'Logout', destroy_user_session_path, class: "logout", method: :delete :javascript $(function(){ diff --git a/app/views/layouts/_project_menu.html.haml b/app/views/layouts/_project_menu.html.haml index 3f58fc5a664..04eaec5accc 100644 --- a/app/views/layouts/_project_menu.html.haml +++ b/app/views/layouts/_project_menu.html.haml @@ -1,37 +1,37 @@ %ul.main_menu - %li.home{:class => project_tab_class} - = link_to @project.code, project_path(@project), :title => "Project" + %li.home{class: project_tab_class} + = link_to @project.code, project_path(@project), title: "Project" - if @project.repo_exists? - if can? current_user, :download_code, @project - %li{:class => tree_tab_class} + %li{class: tree_tab_class} = link_to tree_project_ref_path(@project, @project.root_ref) do Files - %li{:class => commit_tab_class} + %li{class: commit_tab_class} = link_to "Commits", project_commits_path(@project) - %li{:class => tab_class(:network)} + %li{class: tab_class(:network)} = link_to "Network", graph_project_path(@project) - if @project.issues_enabled - %li{:class => tab_class(:issues)} + %li{class: tab_class(:issues)} = link_to project_issues_filter_path(@project) do Issues %span.count.issue_counter= @project.issues.opened.count - if @project.repo_exists? - if @project.merge_requests_enabled - %li{:class => tab_class(:merge_requests)} + %li{class: tab_class(:merge_requests)} = link_to project_merge_requests_path(@project) do Merge Requests %span.count.merge_counter= @project.merge_requests.opened.count - if @project.wall_enabled - %li{:class => tab_class(:wall)} + %li{class: tab_class(:wall)} = link_to wall_project_path(@project) do Wall - if @project.wiki_enabled - %li{:class => tab_class(:wiki)} + %li{class: tab_class(:wiki)} = link_to project_wiki_path(@project, :index) do Wiki diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml index 8de25821ee7..6af0f641fc4 100644 --- a/app/views/layouts/admin.html.haml +++ b/app/views/layouts/admin.html.haml @@ -1,22 +1,22 @@ !!! 5 -%html{ :lang => "en"} +%html{ lang: "en"} = render "layouts/head" - %body{:class => "#{app_theme} admin"} + %body{class: "#{app_theme} admin"} = render "layouts/flash" - = render "layouts/head_panel", :title => "Admin area" + = render "layouts/head_panel", title: "Admin area" .container %ul.main_menu - %li.home{:class => tab_class(:admin_root)} + %li.home{class: tab_class(:admin_root)} = link_to "Stats", admin_root_path - %li{:class => tab_class(:admin_projects)} + %li{class: tab_class(:admin_projects)} = link_to "Projects", admin_projects_path - %li{:class => tab_class(:admin_users)} + %li{class: tab_class(:admin_users)} = link_to "Users", admin_users_path - %li{:class => tab_class(:admin_logs)} + %li{class: tab_class(:admin_logs)} = link_to "Logs", admin_logs_path - %li{:class => tab_class(:admin_emails)} - = link_to "Emails", admin_emails_path - %li{:class => tab_class(:admin_resque)} + %li{class: tab_class(:admin_hooks)} + = link_to "Hooks", admin_hooks_path + %li{class: tab_class(:admin_resque)} = link_to "Resque", admin_resque_path .content= yield diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 0d5d829e00d..dda10d5d137 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -1,10 +1,10 @@ !!! 5 -%html{ :lang => "en"} +%html{ lang: "en"} = render "layouts/head" - %body{:class => "#{app_theme} application"} + %body{class: "#{app_theme} application"} = render "layouts/flash" - = render "layouts/head_panel", :title => "Dashboard" + = render "layouts/head_panel", title: "Dashboard" .container - = render :partial => "layouts/app_menu" + = render partial: "layouts/app_menu" .content = yield diff --git a/app/views/layouts/devise_layout.html.haml b/app/views/layouts/devise_layout.html.haml index c293734b368..70c4f007ba1 100644 --- a/app/views/layouts/devise_layout.html.haml +++ b/app/views/layouts/devise_layout.html.haml @@ -1,6 +1,6 @@ !!! 5 -%html{ :lang => "en"} +%html{ lang: "en"} = render "layouts/head" %body.ui_basic.login-page - = render :partial => "layouts/flash" + = render partial: "layouts/flash" .container= yield diff --git a/app/views/layouts/error.html.haml b/app/views/layouts/error.html.haml index 943dbe778c4..1f5c03bdced 100644 --- a/app/views/layouts/error.html.haml +++ b/app/views/layouts/error.html.haml @@ -1,10 +1,10 @@ !!! 5 -%html{ :lang => "en"} +%html{ lang: "en"} = render "layouts/head" - %body{:class => "#{app_theme} application"} + %body{class: "#{app_theme} application"} = render "layouts/flash" - = render "layouts/head_panel", :title => "" + = render "layouts/head_panel", title: "" .container .content - %br - %h3= yield + %center.padded.prepend-top-20 + = yield diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml index 0cef736c80a..a1938df43a1 100644 --- a/app/views/layouts/notify.html.haml +++ b/app/views/layouts/notify.html.haml @@ -1,6 +1,6 @@ -%html{:lang => "en"} +%html{lang: "en"} %head - %meta{:content => "text/html; charset=utf-8", "http-equiv" => "Content-Type"} + %meta{content: "text/html; charset=utf-8", "http-equiv" => "Content-Type"} %title gitlabhq :css @@ -11,26 +11,29 @@ .content a {color: #0eb6ce; text-decoration: none;} .footer p {font-size: 11px; color:#7d7a7a; margin: 0; padding: 0; font-family: Helvetica, Arial, sans-serif;} .footer a {color: #0eb6ce; text-decoration: none;} - %body{:bgcolor => "#EAEAEA", :style => "margin: 0; padding: 0; background: #EAEAEA"} - %table{:align => "center", :border => "0", :cellpadding => "0", :cellspacing => "0", :style => "padding: 35px 0; background: #EAEAEA;", :width => "100%"} + %body{bgcolor: "#EAEAEA", style: "margin: 0; padding: 0; background: #EAEAEA"} + %table{align: "center", border: "0", cellpadding: "0", cellspacing: "0", style: "padding: 35px 0; background: #EAEAEA;", width: "100%"} %tr - %td{:align => "center", :style => "margin: 0; padding: 0; background: #EAEAEA;"} - %table.header{:align => "center", :border => "0", :cellpadding => "0", :cellspacing => "0", :style => "font-family: Helvetica, Arial, sans-serif; background:#333", :width => "600"} + %td{align: "center", style: "margin: 0; padding: 0; background: #EAEAEA;"} + %table.header{align: "center", border: "0", cellpadding: "0", cellspacing: "0", style: "font-family: Helvetica, Arial, sans-serif; background:#333", width: "600"} %tr - %td{:style => "font-size: 0px;", :width => "20"} + %td{style: "font-size: 0px;", width: "20"} \ - %td{:align => "left", :style => "padding: 18px 0 10px;", :width => "580"} - %h1{:style => "color: #BBBBBB; font: normal 32px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 40px;"} + %td{align: "left", style: "padding: 18px 0 10px;", width: "580"} + %h1{style: "color: #BBBBBB; font: normal 32px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 40px;"} gitlab - if @project | #{@project.name} - %table{:align => "center", :bgcolor => "#fff", :border => "0", :cellpadding => "0", :cellspacing => "0", :style => "font-family: Helvetica, Arial, sans-serif; background: #fff;", :width => "600"} + %table{align: "center", bgcolor: "#fff", border: "0", cellpadding: "0", cellspacing: "0", style: "font-family: Helvetica, Arial, sans-serif; background: #fff;", width: "600"} %tr= yield %tr - %td{:align => "left", :colspan => "2", :height => "3", :style => "padding: font-size: 0; line-height: 0; height: 3px;", :width => "600"} - %table.footer{:align => "center", :border => "0", :cellpadding => "0", :cellspacing => "0", :style => "font-family: Helvetica, Arial, sans-serif; line-height: 10px;", :width => "600"} + %td{align: "left", colspan: "2", height: "3", style: "padding: font-size: 0; line-height: 0; height: 3px;", width: "600"} + %table.footer{align: "center", border: "0", cellpadding: "0", cellspacing: "0", style: "font-family: Helvetica, Arial, sans-serif; line-height: 10px;", width: "600"} %tr - %td{:align => "center", :style => "padding: 5px 0 10px; font-size: 11px; color:#7d7a7a; margin: 0; line-height: 1.2;font-family: Helvetica, Arial, sans-serif;", :valign => "top"} + %td{align: "center", style: "padding: 5px 0 10px; font-size: 11px; color:#7d7a7a; margin: 0; line-height: 1.2;font-family: Helvetica, Arial, sans-serif;", valign: "top"} %br - %p{:style => "font-size: 11px; color:#7d7a7a; margin: 0; padding: 0; font-family: Helvetica, Arial, sans-serif;"} - You're receiving this newsletter because you are in project team. + %p{style: "font-size: 11px; color:#7d7a7a; margin: 0; padding: 0; font-family: Helvetica, Arial, sans-serif;"} + You're receiving this notification because you are a member of the + - if @project + #{@project.name} + project team. diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml index dfe48d68240..b624415dfe1 100644 --- a/app/views/layouts/profile.html.haml +++ b/app/views/layouts/profile.html.haml @@ -1,27 +1,28 @@ !!! 5 -%html{ :lang => "en"} +%html{ lang: "en"} = render "layouts/head" - %body{:class => "#{app_theme} profile"} + %body{class: "#{app_theme} profile"} = render "layouts/flash" - = render "layouts/head_panel", :title => "Profile" + = render "layouts/head_panel", title: "Profile" .container %ul.main_menu - %li.home{:class => tab_class(:profile)} + %li.home{class: tab_class(:profile)} = link_to "Profile", profile_path - %li{:class => tab_class(:password)} + %li{class: tab_class(:password)} = link_to "Password", profile_password_path - %li{:class => tab_class(:token)} + %li{class: tab_class(:ssh_keys)} + = link_to keys_path do + SSH Keys + %span.count= current_user.keys.count + + %li{class: tab_class(:token)} = link_to "Token", profile_token_path - %li{:class => tab_class(:design)} + %li{class: tab_class(:design)} = link_to "Design", profile_design_path - %li{:class => tab_class(:ssh_keys)} - = link_to keys_path do - SSH Keys - %span.count= current_user.keys.count .content = yield diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml index d9843c65fce..56a947d2a9d 100644 --- a/app/views/layouts/project.html.haml +++ b/app/views/layouts/project.html.haml @@ -1,11 +1,11 @@ !!! 5 -%html{ :lang => "en"} +%html{ lang: "en"} = render "layouts/head" - %body{:class => "#{app_theme} project"} + %body{class: "#{app_theme} project"} = render "layouts/flash" - = render "layouts/head_panel", :title => @project.name + = render "layouts/head_panel", title: @project.name .container - = render :partial => "layouts/project_menu" + = render partial: "layouts/project_menu" .content = yield diff --git a/app/views/merge_requests/_form.html.haml b/app/views/merge_requests/_form.html.haml index 4f20a06fd25..b6c12397d6c 100644 --- a/app/views/merge_requests/_form.html.haml +++ b/app/views/merge_requests/_form.html.haml @@ -1,4 +1,4 @@ -= form_for [@project, @merge_request], :html => { :class => "new_merge_request form-horizontal" } do |f| += form_for [@project, @merge_request], html: { class: "new_merge_request form-horizontal" } do |f| -if @merge_request.errors.any? .alert-message.block-message.error %ul @@ -14,9 +14,9 @@ %h5 From (Head Branch) .body .padded - = f.label :source_branch, "From", :class => "control-label" + = f.label :source_branch, "From", class: "control-label" .controls - = f.select(:source_branch, @project.heads.map(&:name), { :include_blank => "Select branch" }, :style => "width:250px") + = f.select(:source_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, style: "width:250px") .bottom_commit .mr_source_commit @@ -25,9 +25,9 @@ %h5 To (Base Branch) .body .padded - = f.label :target_branch, "To", :class => "control-label" + = f.label :target_branch, "To", class: "control-label" .controls - = f.select(:target_branch, @project.heads.map(&:name), { :include_blank => "Select branch" }, :style => "width:250px") + = f.select(:target_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, style: "width:250px") .bottom_commit .mr_target_commit @@ -38,22 +38,22 @@ .top_box_content = f.label :title do %strong= "Title *" - .input= f.text_field :title, :class => "input-xxlarge pad", :maxlength => 255, :rows => 5 + .input= f.text_field :title, class: "input-xxlarge pad", maxlength: 255, rows: 5 .middle_box_content = f.label :assignee_id do %i.icon-user Assign to - .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" }, :style => "width:250px") + .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, style: "width:250px") .control-group .form-actions - = f.submit 'Save', :class => "btn-primary btn" + = f.submit 'Save', class: "btn-primary btn" - if @merge_request.new_record? - = link_to project_merge_requests_path(@project), :class => "btn" do + = link_to project_merge_requests_path(@project), class: "btn" do Cancel - else - = link_to project_merge_request_path(@project, @merge_request), :class => "btn" do + = link_to project_merge_request_path(@project, @merge_request), class: "btn" do Cancel diff --git a/app/views/merge_requests/_head.html.haml b/app/views/merge_requests/_head.html.haml index c578c794060..35a86e6511c 100644 --- a/app/views/merge_requests/_head.html.haml +++ b/app/views/merge_requests/_head.html.haml @@ -1,5 +1,5 @@ .top-tabs - = link_to project_merge_requests_path(@project), :class => "tab #{'active' if current_page?(project_merge_requests_path(@project)) }" do + = link_to project_merge_requests_path(@project), class: "tab #{'active' if current_page?(project_merge_requests_path(@project)) }" do %span Merge Requests diff --git a/app/views/merge_requests/_merge_request.html.haml b/app/views/merge_requests/_merge_request.html.haml index b9a005e08be..7499609066a 100644 --- a/app/views/merge_requests/_merge_request.html.haml +++ b/app/views/merge_requests/_merge_request.html.haml @@ -1,4 +1,4 @@ -%li.wll{ :class => mr_css_classes(merge_request) } +%li.wll{ class: mr_css_classes(merge_request) } .right .left - if merge_request.merged? @@ -14,10 +14,9 @@ = merge_request.source_branch → = merge_request.target_branch - = image_tag gravatar_icon(merge_request.author_email), :class => "avatar" + = image_tag gravatar_icon(merge_request.author_email), class: "avatar" - = link_to project_merge_request_path(merge_request.project, merge_request) do - %p.row_title= truncate(merge_request.title, :length => 80) + %p= link_to_gfm truncate(merge_request.title, length: 80), project_merge_request_path(merge_request.project, merge_request), class: "row_title" %span.update-author %small.cdark= "##{merge_request.id}" diff --git a/app/views/merge_requests/_show.html.haml b/app/views/merge_requests/_show.html.haml index c0b3dd9f5aa..f1b3fa9fe98 100644 --- a/app/views/merge_requests/_show.html.haml +++ b/app/views/merge_requests/_show.html.haml @@ -7,16 +7,16 @@ - if @commits.present? %ul.nav.nav-tabs.mr_nav_tabs %li - = link_to "#notes", "data-url" => project_merge_request_path(@project, @merge_request), :class => "merge-notes-tab tab" do + = link_to "#notes", "data-url" => project_merge_request_path(@project, @merge_request), class: "merge-notes-tab tab" do %i.icon-comment Comments %li - = link_to "#diffs", "data-url" => diffs_project_merge_request_path(@project, @merge_request), :class => "merge-diffs-tab tab" do + = link_to "#diffs", "data-url" => diffs_project_merge_request_path(@project, @merge_request), class: "merge-diffs-tab tab" do %i.icon-list-alt Diff -.merge_request_notes#notes{ :class => (controller.action_name == 'show') ? "" : "hide" } - = render("notes/notes", :tid => @merge_request.id, :tt => "merge_request") +.merge_request_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" } + = render("notes/notes", tid: @merge_request.id, tt: "merge_request") .merge-request-diffs = render "merge_requests/show/diffs" if @diffs .status @@ -33,7 +33,8 @@ }); $(".edit_merge_request").live("ajax:beforeSend", function() { - $(this).replaceWith('#{image_tag "ajax_loader.gif"}'); + $('.can_be_merged').hide(); + $('.merge_in_progress').show(); }) }) diff --git a/app/views/merge_requests/branch_from.js.haml b/app/views/merge_requests/branch_from.js.haml index 3e278015b49..156b4f0dc73 100644 --- a/app/views/merge_requests/branch_from.js.haml +++ b/app/views/merge_requests/branch_from.js.haml @@ -1,2 +1,2 @@ :plain - $(".mr_source_commit").html("#{escape_javascript(render 'commits/commit', :commit => @commit)}"); + $(".mr_source_commit").html("#{escape_javascript(render 'commits/commit', commit: @commit)}"); diff --git a/app/views/merge_requests/branch_to.js.haml b/app/views/merge_requests/branch_to.js.haml index 1ab1f6c43a9..8a201d42088 100644 --- a/app/views/merge_requests/branch_to.js.haml +++ b/app/views/merge_requests/branch_to.js.haml @@ -1,3 +1,3 @@ :plain - $(".mr_target_commit").html("#{escape_javascript(render 'commits/commit', :commit => @commit)}"); + $(".mr_target_commit").html("#{escape_javascript(render 'commits/commit', commit: @commit)}"); diff --git a/app/views/merge_requests/commits.js.haml b/app/views/merge_requests/commits.js.haml index 2055aa9b4bd..76322bdb210 100644 --- a/app/views/merge_requests/commits.js.haml +++ b/app/views/merge_requests/commits.js.haml @@ -1,4 +1,4 @@ :plain - $(".merge-request-commits").html("#{escape_javascript(render(:partial => "commits"))}"); + $(".merge-request-commits").html("#{escape_javascript(render(partial: "commits"))}"); diff --git a/app/views/merge_requests/diffs.js.haml b/app/views/merge_requests/diffs.js.haml index 4be5ec132e3..b147e5be71c 100644 --- a/app/views/merge_requests/diffs.js.haml +++ b/app/views/merge_requests/diffs.js.haml @@ -1,4 +1,4 @@ :plain - $(".merge-request-diffs").html("#{escape_javascript(render(:partial => "merge_requests/show/diffs"))}"); + $(".merge-request-diffs").html("#{escape_javascript(render(partial: "merge_requests/show/diffs"))}"); diff --git a/app/views/merge_requests/index.html.haml b/app/views/merge_requests/index.html.haml index 5210b95e3e4..4ad6e5c18ce 100644 --- a/app/views/merge_requests/index.html.haml +++ b/app/views/merge_requests/index.html.haml @@ -1,7 +1,7 @@ %h3.page_title Merge Requests - if can? current_user, :write_issue, @project - = link_to new_project_merge_request_path(@project), :class => "right btn small", :title => "New Merge Request" do + = link_to new_project_merge_request_path(@project), class: "right btn small", title: "New Merge Request" do New Merge Request %br @@ -10,17 +10,17 @@ .ui-box .title %ul.nav.nav-pills - %li{:class => ("active" if (params[:f] == "0" || !params[:f]))} - = link_to project_merge_requests_path(@project, :f => 0) do + %li{class: ("active" if (params[:f] == "0" || !params[:f]))} + = link_to project_merge_requests_path(@project, f: 0) do Open - %li{:class => ("active" if params[:f] == "2")} - = link_to project_merge_requests_path(@project, :f => 2) do + %li{class: ("active" if params[:f] == "2")} + = link_to project_merge_requests_path(@project, f: 2) do Closed - %li{:class => ("active" if params[:f] == "3")} - = link_to project_merge_requests_path(@project, :f => 3) do + %li{class: ("active" if params[:f] == "3")} + = link_to project_merge_requests_path(@project, f: 3) do To Me - %li{:class => ("active" if params[:f] == "1")} - = link_to project_merge_requests_path(@project, :f => 1) do + %li{class: ("active" if params[:f] == "1")} + = link_to project_merge_requests_path(@project, f: 1) do All %ul.unstyled @@ -31,7 +31,7 @@ - if @merge_requests.present? %li.bottom .row - .span7= paginate @merge_requests, :theme => "gitlab" + .span7= paginate @merge_requests, theme: "gitlab" .span4.right %span.cgray.right #{@merge_requests.total_count} merge requests for this filter diff --git a/app/views/merge_requests/show.js.haml b/app/views/merge_requests/show.js.haml index 2922b3bc6f0..7a27b166849 100644 --- a/app/views/merge_requests/show.js.haml +++ b/app/views/merge_requests/show.js.haml @@ -1,2 +1,2 @@ :plain - $(".merge-request-notes").html("#{escape_javascript(render("notes/notes", :tid => @merge_request.id, :tt => "merge_request"))}"); + $(".merge-request-notes").html("#{escape_javascript(render("notes/notes", tid: @merge_request.id, tt: "merge_request"))}"); diff --git a/app/views/merge_requests/show/_commits.html.haml b/app/views/merge_requests/show/_commits.html.haml index d10e8fd597a..d25e707c64e 100644 --- a/app/views/merge_requests/show/_commits.html.haml +++ b/app/views/merge_requests/show/_commits.html.haml @@ -7,19 +7,19 @@ - if @commits.count > 8 %ul.first_mr_commits.unstyled - @commits.first(8).each do |commit| - = render "commits/commit", :commit => commit + = render "commits/commit", commit: commit %li.bottom 8 of #{@commits.count} commits displayed. %strong %a.mr_show_all_commits Click here to show all %ul.all_mr_commits.hide.unstyled - @commits.each do |commit| - = render "commits/commit", :commit => commit + = render "commits/commit", commit: commit - else %ul.unstyled - @commits.each do |commit| - = render "commits/commit", :commit => commit + = render "commits/commit", commit: commit - else %h5 diff --git a/app/views/merge_requests/show/_diffs.html.haml b/app/views/merge_requests/show/_diffs.html.haml index 80776f19132..7685090311a 100644 --- a/app/views/merge_requests/show/_diffs.html.haml +++ b/app/views/merge_requests/show/_diffs.html.haml @@ -1,8 +1,8 @@ - if @merge_request.valid_diffs? - = render "commits/diffs", :diffs => @diffs + = render "commits/diffs", diffs: @diffs - elsif @merge_request.broken_diffs? %h4.nothing_here_message Can't load diff. - You can #{link_to "download MR patch", raw_project_merge_request_path(@project, @merge_request), :class => "vlink"} instead. + You can #{link_to "download MR patch", raw_project_merge_request_path(@project, @merge_request), class: "vlink"} instead. - else %h4.nothing_here_message Nothing to merge diff --git a/app/views/merge_requests/show/_how_to_merge.html.haml b/app/views/merge_requests/show/_how_to_merge.html.haml index 2512d254fe0..69881d4352f 100644 --- a/app/views/merge_requests/show/_how_to_merge.html.haml +++ b/app/views/merge_requests/show/_how_to_merge.html.haml @@ -1,15 +1,14 @@ %div#modal_merge_info.modal.hide .modal-header - %a.close{:href => "#"} × + %a.close{href: "#"} × %h3 How To Merge .modal-body - %pre + %pre.dark = preserve do - :erb - git checkout <%= @merge_request.target_branch %> - git fetch origin - git merge origin/<%= @merge_request.source_branch %> - git push origin <%= @merge_request.target_branch %> + git checkout #{@merge_request.target_branch} + git fetch origin + git merge origin/#{@merge_request.source_branch} + git push origin #{@merge_request.target_branch} :javascript diff --git a/app/views/merge_requests/show/_mr_accept.html.haml b/app/views/merge_requests/show/_mr_accept.html.haml index c158ef88bba..f24228856ff 100644 --- a/app/views/merge_requests/show/_mr_accept.html.haml +++ b/app/views/merge_requests/show/_mr_accept.html.haml @@ -4,31 +4,31 @@ - if @merge_request.open? && @commits.any? && can?(current_user, :accept_mr, @project) - .automerge_widget.can_be_merged{:style => "display:none"} + .automerge_widget.can_be_merged{style: "display:none"} .alert.alert-success %span - = form_for [:automerge, @project, @merge_request], :remote => true, :method => :get do |f| + = form_for [:automerge, @project, @merge_request], remote: true, method: :get do |f| %p You can accept this request automatically. If you still want to do it manually - - %strong= link_to "click here", "#", :class => "how_to_merge_link vlink", :title => "How To Merge" + %strong= link_to "click here", "#", class: "how_to_merge_link vlink", title: "How To Merge" for instructions .accept_group - = f.submit "Accept Merge Request", :class => "btn small success accept_merge_request" + = f.submit "Accept Merge Request", class: "btn small success accept_merge_request" - unless @project.root_ref? @merge_request.source_branch .remove_branch_holder - = label_tag :should_remove_source_branch, :class => "checkbox" do + = label_tag :should_remove_source_branch, class: "checkbox" do = check_box_tag :should_remove_source_branch Remove source-branch .clearfix - .automerge_widget.cannot_be_merged{:style => "display:none"} + .automerge_widget.cannot_be_merged{style: "display:none"} .alert.alert-info %span - = link_to "Show how to merge", "#", :class => "how_to_merge_link btn small padded", :title => "How To Merge" + = link_to "Show how to merge", "#", class: "how_to_merge_link btn small padded", title: "How To Merge" - %strong This request cant be merged with GitLab. You should do it manually + %strong This request can't be merged with GitLab. You should do it manually .automerge_widget.unchecked .alert-message @@ -36,7 +36,10 @@ %i.icon-refresh Checking for ability to automatically merge… - .automerge_widget.already_cannot_be_merged{:style => "display:none"} + .automerge_widget.already_cannot_be_merged{style: "display:none"} .alert.alert-info %strong This merge request already can not be merged. Try to reload page. + .merge_in_progress.hide + %span.cgray Merge is in progress. Please wait. Page will be automatically reloaded. + = image_tag "ajax_loader.gif" diff --git a/app/views/merge_requests/show/_mr_box.html.haml b/app/views/merge_requests/show/_mr_box.html.haml index b542dac98e0..81ab83f3436 100644 --- a/app/views/merge_requests/show/_mr_box.html.haml +++ b/app/views/merge_requests/show/_mr_box.html.haml @@ -5,17 +5,17 @@ .alert-message.error.status_info Closed - else .alert-message.success.status_info Open - = @merge_request.title + = gfm @merge_request.title .middle_box_content %div %cite.cgray Created at #{@merge_request.created_at.stamp("Aug 21, 2011")} by - = image_tag gravatar_icon(@merge_request.author_email), :width => 16, :class => "lil_av" + = image_tag gravatar_icon(@merge_request.author_email), width: 16, class: "lil_av" %strong.author= link_to_merge_request_author(@merge_request) - if @merge_request.assignee %cite.cgray and currently assigned to - = image_tag gravatar_icon(@merge_request.assignee_email), :width => 16, :class => "lil_av" + = image_tag gravatar_icon(@merge_request.assignee_email), width: 16, class: "lil_av" %strong.author= link_to_merge_request_assignee(@merge_request) diff --git a/app/views/merge_requests/show/_mr_title.html.haml b/app/views/merge_requests/show/_mr_title.html.haml index 3f6060b0645..31fa0779fd2 100644 --- a/app/views/merge_requests/show/_mr_title.html.haml +++ b/app/views/merge_requests/show/_mr_title.html.haml @@ -13,13 +13,13 @@ = "MERGED" - if can?(current_user, :modify_merge_request, @merge_request) - if @merge_request.open? - = link_to raw_project_merge_request_path(@project, @merge_request), :class => "btn grouped" do + = link_to raw_project_merge_request_path(@project, @merge_request), class: "btn grouped" do %i.icon-download-alt Get Patch - = link_to 'Close', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => true }, :status_only => true), :method => :put, :class => "btn grouped danger", :title => "Close merge request" + = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {closed: true }, status_only: true), method: :put, class: "btn grouped danger", title: "Close merge request" - = link_to edit_project_merge_request_path(@project, @merge_request), :class => "btn grouped" do + = link_to edit_project_merge_request_path(@project, @merge_request), class: "btn grouped" do %i.icon-edit Edit diff --git a/app/views/milestones/_form.html.haml b/app/views/milestones/_form.html.haml index 69567eff417..1cd08ac3bcf 100644 --- a/app/views/milestones/_form.html.haml +++ b/app/views/milestones/_form.html.haml @@ -1,11 +1,11 @@ -%h3= @milestone.new_record? ? "New Milestone" : "Edit Milestone ##{@milestone.id}" +%h3.page_title= @milestone.new_record? ? "New Milestone" : "Edit Milestone ##{@milestone.id}" .back_link = link_to project_milestones_path(@project) do ← To milestones %hr -= form_for [@project, @milestone], :html => {:class => "new_milestone form-horizontal"} do |f| += form_for [@project, @milestone], html: {class: "new_milestone form-horizontal"} do |f| -if @milestone.errors.any? .alert-message.block-message.error %ul @@ -14,35 +14,35 @@ .row .span6 .control-group - = f.label :title, "Title", :class => "control-label" + = f.label :title, "Title", class: "control-label" .controls - = f.text_field :title, :maxlength => 255, :class => "input-xlarge" - %p.help-block Required + = f.text_field :title, maxlength: 255, class: "input-xlarge" + %p.hint Required .control-group - = f.label :description, "Description", :class => "control-label" + = f.label :description, "Description", class: "control-label" .controls - = f.text_area :description, :maxlength => 2000, :class => "input-xlarge", :rows => 10 - %p.help-block Markdown is enabled. + = f.text_area :description, maxlength: 2000, class: "input-xlarge", rows: 10 + %p.hint Markdown is enabled. .span6 .control-group - = f.label :due_date, "Due Date", :class => "control-label" + = f.label :due_date, "Due Date", class: "control-label" .input= f.hidden_field :due_date .controls .datepicker .form-actions - if @milestone.new_record? - = f.submit 'Create milestone', :class => "primary btn" + = f.submit 'Create milestone', class: "primary btn" -else - = f.submit 'Save changes', :class => "primary btn" + = f.submit 'Save changes', class: "primary btn" - if request.xhr? - = link_to "Cancel", "#back", :onclick => "backToIssues();", :class => "btn" + = link_to "Cancel", "#back", onclick: "backToIssues();", class: "btn" - else - if @milestone.new_record? - = link_to "Cancel", project_milestones_path(@project), :class => "btn" + = link_to "Cancel", project_milestones_path(@project), class: "btn" - else - = link_to "Cancel", project_milestone_path(@project, @milestone), :class => "btn" + = link_to "Cancel", project_milestone_path(@project, @milestone), class: "btn" :javascript $(function() { diff --git a/app/views/milestones/_milestone.html.haml b/app/views/milestones/_milestone.html.haml index 9912cf9ed54..205b864f80f 100644 --- a/app/views/milestones/_milestone.html.haml +++ b/app/views/milestones/_milestone.html.haml @@ -1,19 +1,18 @@ -%li{:class => "milestone", :id => dom_id(milestone) } +%li{class: "milestone", id: dom_id(milestone) } .right - if milestone.issues.any? %span.btn.small.disabled.grouped= pluralize milestone.issues.count, 'issues' - if milestone.issues.count > 0 - = link_to 'Browse Issues', project_issues_path(milestone.project, :milestone_id => milestone.id), :class => "btn small grouped" + = link_to 'Browse Issues', project_issues_path(milestone.project, milestone_id: milestone.id), class: "btn small grouped" - if can? current_user, :admin_milestone, milestone.project - = link_to 'Edit', edit_project_milestone_path(milestone.project, milestone), :class => "btn small edit-milestone-link grouped" - = link_to project_milestone_path(milestone.project, milestone) do - %h4.row_title - = truncate(milestone.title, :length => 100) - %small - = milestone.expires_at - %br - .progress.progress-success.span3 - .bar{:style => "width: #{milestone.percent_complete}%;"} + = link_to 'Edit', edit_project_milestone_path(milestone.project, milestone), class: "btn small edit-milestone-link grouped" + %h4 + = link_to_gfm truncate(milestone.title, length: 100), project_milestone_path(milestone.project, milestone), class: "row_title" + %small + = milestone.expires_at + %br + .progress.progress-success.span3 + .bar{style: "width: #{milestone.percent_complete}%;"} diff --git a/app/views/milestones/index.html.haml b/app/views/milestones/index.html.haml index ed85166fbb2..ecb008dc144 100644 --- a/app/views/milestones/index.html.haml +++ b/app/views/milestones/index.html.haml @@ -3,23 +3,23 @@ %h3.page_title Milestones - if can? current_user, :admin_milestone, @project - = link_to "New Milestone", new_project_milestone_path(@project), :class => "right btn small", :title => "New Milestone" + = link_to "New Milestone", new_project_milestone_path(@project), class: "right btn small", title: "New Milestone" %br %div.ui-box .title %ul.nav.nav-pills - %li{:class => ("active" if (params[:f] == "0" || !params[:f]))} - = link_to project_milestones_path(@project, :f => 0) do + %li{class: ("active" if (params[:f] == "0" || !params[:f]))} + = link_to project_milestones_path(@project, f: 0) do Active - %li{:class => ("active" if params[:f] == "1")} - = link_to project_milestones_path(@project, :f => 1) do + %li{class: ("active" if params[:f] == "1")} + = link_to project_milestones_path(@project, f: 1) do All %ul.unstyled = render @milestones - if @milestones.present? - %li.bottom= paginate @milestones, :remote => true, :theme => "gitlab" + %li.bottom= paginate @milestones, remote: true, theme: "gitlab" - else %li %h3.nothing_here_message Nothing to show here diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml index dc3dcd01de8..b7da7b668ea 100644 --- a/app/views/milestones/show.html.haml +++ b/app/views/milestones/show.html.haml @@ -4,9 +4,9 @@ = @milestone.expires_at %span.right - = link_to 'Browse Issues', project_issues_path(@milestone.project, :milestone_id => @milestone.id), :class => "btn edit-milestone-link small grouped" + = link_to 'Browse Issues', project_issues_path(@milestone.project, milestone_id: @milestone.id), class: "btn edit-milestone-link small grouped" - if can?(current_user, :admin_milestone, @project) - = link_to edit_project_milestone_path(@project, @milestone), :class => "btn small grouped" do + = link_to edit_project_milestone_path(@project, @milestone), class: "btn small grouped" do %i.icon-edit Edit @@ -21,7 +21,7 @@ .alert-message.error.status_info Closed - else .alert-message.success.status_info Open - = @milestone.title + = gfm @milestone.title %small.right= @milestone.expires_at .middle_box_content @@ -32,7 +32,7 @@ – #{@milestone.issues.closed.count} closed .progress.progress-success - .bar{:style => "width: #{@milestone.percent_complete}%;"} + .bar{style: "width: #{@milestone.percent_complete}%;"} - if @milestone.description.present? @@ -50,10 +50,10 @@ %td = link_to [@project, issue] do %span.badge.badge-info ##{issue.id} - – - = truncate issue.title, :length => 60 + – + = link_to_gfm truncate(issue.title, length: 60), [@project, issue] %br - = paginate @issues, :theme => "gitlab" + = paginate @issues, theme: "gitlab" .span6 %table.admin-table @@ -62,6 +62,6 @@ - @users.each do |user| %tr %td - = image_tag gravatar_icon(user.email, 24), :width => "24" + = image_tag gravatar_icon(user.email, 24), width: "24" = user.name diff --git a/app/views/notes/_create_common.js.haml b/app/views/notes/_create_common.js.haml index 583812bf502..e9538902754 100644 --- a/app/views/notes/_create_common.js.haml +++ b/app/views/notes/_create_common.js.haml @@ -1,8 +1,10 @@ - if note.valid? :plain - $("#new_note .errors").remove(); + $("#new_note .error").remove(); $('#new_note textarea').val(""); - NoteList.prepend(#{note.id}, "#{escape_javascript(render :partial => "notes/show", :locals => {:note => note})}"); + $('#preview-link').text('Preview'); + $('#preview-note').hide(); $('#note_note').show(); + NoteList.prepend(#{note.id}, "#{escape_javascript(render partial: "notes/show", locals: {note: note})}"); - else :plain $("#new_note").replaceWith("#{escape_javascript(render('form'))}"); diff --git a/app/views/notes/_create_line.js.haml b/app/views/notes/_create_line.js.haml index 9cf085cd613..13809bec1b9 100644 --- a/app/views/notes/_create_line.js.haml +++ b/app/views/notes/_create_line.js.haml @@ -4,5 +4,5 @@ $('#new_note textarea').val(""); $("a.line_note_reply_link[line_code='#{note.line_code}']").closest("tr").remove(); var trEl = $(".#{note.line_code}").parent(); - trEl.after("#{escape_javascript(render :partial => "notes/per_line_show", :locals => {:note => note})}"); - trEl.after("#{escape_javascript(render :partial => "notes/reply_button", :locals => {:line_code => note.line_code})}"); + trEl.after("#{escape_javascript(render partial: "notes/per_line_show", locals: {note: note})}"); + trEl.after("#{escape_javascript(render partial: "notes/reply_button", locals: {line_code: note.line_code})}"); diff --git a/app/views/notes/_form.html.haml b/app/views/notes/_form.html.haml index f5aa1495796..dac026bd23d 100644 --- a/app/views/notes/_form.html.haml +++ b/app/views/notes/_form.html.haml @@ -1,5 +1,5 @@ -= form_for [@project, @note], :remote => "true", :multipart => true do |f| - %h3 Leave a comment += form_for [@project, @note], remote: "true", multipart: true do |f| + %h3.page_title Leave a comment -if @note.errors.any? .alert-message.block-message.error - @note.errors.full_messages.each do |msg| @@ -7,29 +7,32 @@ = f.hidden_field :noteable_id = f.hidden_field :noteable_type - = f.text_area :note, :size => 255 - %p.hint Markdown is enabled. + = f.text_area :note, size: 255 + #preview-note.well.hide + %p.hint + = link_to "Gitlab Markdown", help_markdown_path, target: '_blank' + is enabled. + = link_to 'Preview', preview_project_notes_path(@project), id: 'preview-link' .row.note_advanced_opts.hide - .span4 - %h5 Notify via email: - .clearfix - = label_tag :notify do - = check_box_tag :notify, 1, @note.noteable_type != "Commit" - %span Project team + .span2 + = f.submit 'Add Comment', class: "btn primary submit_note", id: "submit_note" + .span4.notify_opts + %h6.left Notify via email: + = label_tag :notify do + = check_box_tag :notify, 1, @note.noteable_type != "Commit" + %span Project team - - if @note.notify_only_author?(current_user) - = label_tag :notify_author do - = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit" - %span Commit author - .span8 - %h5 Attachment: - .clearfix - .attachments - %div.file_name File name... - %button.file_upload.btn.small Upload File - .input= f.file_field :attachment, :class => "input-file" - %span Any file less than 10 MB + - if @note.notify_only_author?(current_user) + = label_tag :notify_author do + = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit" + %span Commit author + .span6.attachments + %h6.left Attachment: + %span.file_name File name... + + .input.input_file + %a.file_upload.btn.small Upload File + = f.file_field :attachment, class: "input-file" + %span.hint Any file less than 10 MB - - = f.submit 'Add Comment', :class => "btn primary submit_note", :id => "submit_note" diff --git a/app/views/notes/_load.js.haml b/app/views/notes/_load.js.haml index 1f3559670d1..c16a699a1b7 100644 --- a/app/views/notes/_load.js.haml +++ b/app/views/notes/_load.js.haml @@ -1,15 +1,15 @@ - unless @notes.blank? - if params[:last_id] :plain - NoteList.replace("#{escape_javascript(render(:partial => 'notes/notes_list'))}"); + NoteList.replace("#{escape_javascript(render(partial: 'notes/notes_list'))}"); - elsif params[:first_id] :plain - NoteList.append(#{@notes.last.id}, "#{escape_javascript(render(:partial => 'notes/notes_list'))}"); + NoteList.append(#{@notes.last.id}, "#{escape_javascript(render(partial: 'notes/notes_list'))}"); - else :plain - NoteList.setContent(#{@notes.last.id}, #{@notes.first.id}, "#{escape_javascript(render(:partial => 'notes/notes_list'))}"); + NoteList.setContent(#{@notes.last.id}, #{@notes.first.id}, "#{escape_javascript(render(partial: 'notes/notes_list'))}"); - else - if params[:first_id] diff --git a/app/views/notes/_notes_list.html.haml b/app/views/notes/_notes_list.html.haml index 1e4a6bb2b2f..5673988d87d 100644 --- a/app/views/notes/_notes_list.html.haml +++ b/app/views/notes/_notes_list.html.haml @@ -1,4 +1,4 @@ - @notes.each do |note| - next unless note.author - = render :partial => "notes/show", :locals => {:note => note} + = render partial: "notes/show", locals: {note: note} diff --git a/app/views/notes/_per_line_form.html.haml b/app/views/notes/_per_line_form.html.haml index 8beaf9b5e0c..afb0b30dca3 100644 --- a/app/views/notes/_per_line_form.html.haml +++ b/app/views/notes/_per_line_form.html.haml @@ -1,8 +1,8 @@ -%table{:style => "display:none;"} +%table{style: "display:none;"} %tr.per_line_form - %td{:colspan => 3 } - = form_for [@project, @note], :remote => "true", :multipart => true do |f| - %h3 Leave a note + %td{colspan: 3 } + = form_for [@project, @note], remote: "true", multipart: true do |f| + %h3.page_title Leave a note %div.span10 -if @note.errors.any? .alert-message.block-message.error @@ -12,20 +12,22 @@ = f.hidden_field :noteable_id = f.hidden_field :noteable_type = f.hidden_field :line_code - = f.text_area :note, :size => 255 - %h5 Notify via email: - .clearfix - = label_tag :notify do - = check_box_tag :notify, 1, @note.noteable_type != "Commit" - %span Project team + = f.text_area :note, size: 255 + .note_actions + .buttons + = f.submit 'Add note', class: "btn primary submit_note", id: "submit_note" + = link_to "Cancel", "#", class: "btn hide-button" + .options + %h6.left Notify via email: + .labels + = label_tag :notify do + = check_box_tag :notify, 1, @note.noteable_type != "Commit" + %span Project team - - if @note.notify_only_author?(current_user) - = label_tag :notify_author do - = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit" - %span Commit author - .actions - = f.submit 'Add note', :class => "btn primary submit_note", :id => "submit_note" - = link_to "Close", "#", :class => "btn hide-button" + - if @note.notify_only_author?(current_user) + = label_tag :notify_author do + = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit" + %span Commit author :javascript $(function(){ diff --git a/app/views/notes/_per_line_show.html.haml b/app/views/notes/_per_line_show.html.haml index e239c618b11..cf1769c0517 100644 --- a/app/views/notes/_per_line_show.html.haml +++ b/app/views/notes/_per_line_show.html.haml @@ -1,5 +1,5 @@ %tr.line_notes_row - %td{:colspan => 3} + %td{colspan: 3} %ul - = render :partial => "notes/show", :locals => {:note => note} + = render partial: "notes/show", locals: {note: note} diff --git a/app/views/notes/_reply_button.html.haml b/app/views/notes/_reply_button.html.haml index db6b35b7ada..c981fb9fc72 100644 --- a/app/views/notes/_reply_button.html.haml +++ b/app/views/notes/_reply_button.html.haml @@ -1,4 +1,4 @@ %tr.line_notes_row.reply - %td{:colspan => 3} + %td{colspan: 3} %i.icon-comment - = link_to "Reply", "#", :class => "line_note_reply_link", "line_code" => line_code, :title => "Add note for this line" + = link_to "Reply", "#", class: "line_note_reply_link", "line_code" => line_code, title: "Add note for this line" diff --git a/app/views/notes/_show.html.haml b/app/views/notes/_show.html.haml index 3cd72c38929..3412e4ebae5 100644 --- a/app/views/notes/_show.html.haml +++ b/app/views/notes/_show.html.haml @@ -1,5 +1,5 @@ -%li{:id => dom_id(note), :class => "note"} - = image_tag gravatar_icon(note.author.email), :class => "left", :width => 40, :style => "padding-right:5px;" +%li{id: dom_id(note), class: "note"} + = image_tag gravatar_icon(note.author.email), class: "avatar s32" %div.note-author %strong= note.author_name = link_to "##{dom_id(note)}", name: dom_id(note) do @@ -7,7 +7,9 @@ = time_ago_in_words(note.updated_at) ago - if(note.author_id == current_user.id) || can?(current_user, :admin_note, @project) - %strong= link_to "Remove", [@project, note], :confirm => 'Are you sure?', :method => :delete, :remote => true, :class => "cred delete-note btn small" + = link_to [@project, note], confirm: 'Are you sure?', method: :delete, remote: true, class: "cred delete-note btn very_small" do + %i.icon-trash + Remove %div.note-title = preserve do @@ -15,5 +17,5 @@ - if note.attachment.url .right %div.file - = link_to note.attachment_identifier, note.attachment.url, :target => "_blank" + = link_to note.attachment_identifier, note.attachment.url, target: "_blank" .clear diff --git a/app/views/notes/create.js.haml b/app/views/notes/create.js.haml index e87dbcf63c1..8f631f38f79 100644 --- a/app/views/notes/create.js.haml +++ b/app/views/notes/create.js.haml @@ -1,7 +1,7 @@ - if @note.line_code - = render "create_line", :note => @note + = render "create_line", note: @note - else - = render "create_common", :note => @note + = render "create_common", note: @note -# Enable submit button :plain diff --git a/app/views/notify/new_issue_email.html.haml b/app/views/notify/new_issue_email.html.haml index dd6f50c0686..654d6cd12be 100644 --- a/app/views/notify/new_issue_email.html.haml +++ b/app/views/notify/new_issue_email.html.haml @@ -1,16 +1,15 @@ -%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"} - %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"} +%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} + %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} %tr - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} - %td{:align => "left", :style => "padding: 20px 0 0;"} - %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{align: "left", style: "padding: 20px 0 0;"} + %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} New Issue was created and assigned to you. - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} %tr - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} - %td{:align => "left", :style => "padding: 20px 0 0;"} - %h2{:style => "color:#646464 !important; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} - = link_to project_issue_url(@issue.project, @issue), :title => @issue.title do - = "Issue ##{@issue.id.to_s}" - = truncate(@issue.title, :length => 45) + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{align: "left", style: "padding: 20px 0 0;"} + %h2{style: "color:#646464 !important; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} + = "Issue ##{@issue.id}" + = link_to_gfm truncate(@issue.title, length: 45), project_issue_url(@issue.project, @issue), title: @issue.title %br diff --git a/app/views/notify/new_merge_request_email.html.haml b/app/views/notify/new_merge_request_email.html.haml index f7ec01e84b3..151aac451fb 100644 --- a/app/views/notify/new_merge_request_email.html.haml +++ b/app/views/notify/new_merge_request_email.html.haml @@ -1,18 +1,18 @@ -%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"} - %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"} +%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} + %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} %tr - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} - %td{:align => "left", :style => "padding: 20px 0 0;"} - %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} - New Merge Request - = link_to truncate(@merge_request.title, :length => 16), project_merge_request_url(@merge_request.project, @merge_request) - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{align: "left", style: "padding: 20px 0 0;"} + %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} + = "New Merge Request !#{@merge_request.id}" + = link_to_gfm truncate(@merge_request.title, length: 16), project_merge_request_url(@merge_request.project, @merge_request) + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} %tr - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} - %td{:style => "padding: 15px 0 15px;", :valign => "top"} - %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{style: "padding: 15px 0 15px;", valign: "top"} + %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} Branches: #{@merge_request.source_branch} → #{@merge_request.target_branch} - %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} + %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} Asignee: #{@merge_request.author_name} → #{@merge_request.assignee_name} %td diff --git a/app/views/notify/new_user_email.html.haml b/app/views/notify/new_user_email.html.haml index b0f198a50fd..d96afc92fe2 100644 --- a/app/views/notify/new_user_email.html.haml +++ b/app/views/notify/new_user_email.html.haml @@ -1,23 +1,23 @@ -%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"} - %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"} +%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} + %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} %tr - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} - %td{:align => "left", :style => "padding: 20px 0 0;"} - %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{align: "left", style: "padding: 20px 0 0;"} + %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} Hi #{@user['name']}! - %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} + %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} Administrator created account for you. Now you are a member of company gitlab application. - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} %tr - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} - %td{:style => "padding: 15px 0 15px;", :valign => "top"} - %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 28px; font-size: 16px;font-family: Helvetica, Arial, sans-serif; "} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{style: "padding: 15px 0 15px;", valign: "top"} + %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 28px; font-size: 16px;font-family: Helvetica, Arial, sans-serif; "} login.......................................... %code= @user['email'] - %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 28px; font-size: 16px;font-family: Helvetica, Arial, sans-serif; "} + %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 28px; font-size: 16px;font-family: Helvetica, Arial, sans-serif; "} password.................................. %code= @password - %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 28px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} + %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 28px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} = link_to "Click here to login", root_url - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} diff --git a/app/views/notify/note_commit_email.html.haml b/app/views/notify/note_commit_email.html.haml index 99b89632ea4..e87f9c120e4 100644 --- a/app/views/notify/note_commit_email.html.haml +++ b/app/views/notify/note_commit_email.html.haml @@ -1,23 +1,23 @@ -%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"} - %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"} +%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} + %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} %tr - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} - %td{:align => "left", :style => "padding: 20px 0 0;"} - %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} - New comment for commit - = link_to truncate(@commit.id.to_s, :length => 16), project_commit_url(@note.project, :id => @commit.id, :anchor => "note_#{@note.id}") - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{align: "left", style: "padding: 20px 0 0;"} + %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} + = "New comment for Commit #{@commit.short_id}" + = link_to_gfm truncate(@commit.title, length: 16), project_commit_url(@note.project, id: @commit.id, anchor: "note_#{@note.id}") + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} %tr - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} - %td{:style => "padding: 15px 0 15px;", :valign => "top"} - %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} - %a{:href => "#", :style => "color: #0eb6ce; text-decoration: none;"} #{@note.author_name} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{style: "padding: 15px 0 15px;", valign: "top"} + %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} + %a{href: "#", style: "color: #0eb6ce; text-decoration: none;"} #{@note.author_name} left next message: %br - %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :width => "558"} + %table{border: "0", cellpadding: "0", cellspacing: "0", width: "558"} %tr - %td{:valign => "top"} - %div{ :style => "background:#f5f5f5; padding:20px;border:1px solid #ddd" } + %td{valign: "top"} + %div{ style: "background:#f5f5f5; padding:20px;border:1px solid #ddd" } = markdown(@note.note) - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} diff --git a/app/views/notify/note_issue_email.html.haml b/app/views/notify/note_issue_email.html.haml index 17d58bdec73..832f5df4463 100644 --- a/app/views/notify/note_issue_email.html.haml +++ b/app/views/notify/note_issue_email.html.haml @@ -1,25 +1,23 @@ -%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"} - %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"} +%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} + %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} %tr - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} - %td{:align => "left", :style => "padding: 20px 0 0;"} - %h2{:style => "color:#646464 !important; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} - New comment - - = link_to project_issue_url(@issue.project, @issue, :anchor => "note_#{@note.id}") do - = "Issue ##{@issue.id.to_s}" - = truncate(@issue.title, :length => 35) - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{align: "left", style: "padding: 20px 0 0;"} + %h2{style: "color:#646464 !important; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} + = "New comment for Issue ##{@issue.id}" + = link_to_gfm truncate(@issue.title, length: 35), project_issue_url(@issue.project, @issue, anchor: "note_#{@note.id}") + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} %tr - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} - %td{:style => "padding: 15px 0 15px;", :valign => "top"} - %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} - %a{:href => "#", :style => "color: #0eb6ce; text-decoration: none;"} #{@note.author_name} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{style: "padding: 15px 0 15px;", valign: "top"} + %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} + %a{href: "#", style: "color: #0eb6ce; text-decoration: none;"} #{@note.author_name} left next message: %br - %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :width => "558"} + %table{border: "0", cellpadding: "0", cellspacing: "0", width: "558"} %tr - %td{:valign => "top"} - %div{ :style => "background:#f5f5f5; padding:20px;border:1px solid #ddd" } + %td{valign: "top"} + %div{ style: "background:#f5f5f5; padding:20px;border:1px solid #ddd" } = markdown(@note.note) - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} diff --git a/app/views/notify/note_merge_request_email.html.haml b/app/views/notify/note_merge_request_email.html.haml index 9c2284a6457..764cd094b76 100644 --- a/app/views/notify/note_merge_request_email.html.haml +++ b/app/views/notify/note_merge_request_email.html.haml @@ -1,23 +1,23 @@ -%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"} - %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"} +%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} + %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} %tr - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} - %td{:align => "left", :style => "padding: 20px 0 0;"} - %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} - New comment for Merge Request - = link_to truncate(@merge_request.title, :length => 16), project_merge_request_url(@merge_request.project, @merge_request, :anchor => "note_#{@note.id}") - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{align: "left", style: "padding: 20px 0 0;"} + %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} + = "New comment for Merge Request !#{@merge_request.id}" + = link_to_gfm truncate(@merge_request.title, length: 16), project_merge_request_url(@merge_request.project, @merge_request, anchor: "note_#{@note.id}") + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} %tr - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} - %td{:style => "padding: 15px 0 15px;", :valign => "top"} - %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} - %a{:href => "#", :style => "color: #0eb6ce; text-decoration: none;"} #{@note.author_name} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{style: "padding: 15px 0 15px;", valign: "top"} + %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} + %a{href: "#", style: "color: #0eb6ce; text-decoration: none;"} #{@note.author_name} left next message: %br - %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :width => "558"} + %table{border: "0", cellpadding: "0", cellspacing: "0", width: "558"} %tr - %td{:valign => "top"} - %div{ :style => "background:#f5f5f5; padding:20px;border:1px solid #ddd" } + %td{valign: "top"} + %div{ style: "background:#f5f5f5; padding:20px;border:1px solid #ddd" } = markdown(@note.note) - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} diff --git a/app/views/notify/note_wall_email.html.haml b/app/views/notify/note_wall_email.html.haml index f62e1f917cd..0661c5801b8 100644 --- a/app/views/notify/note_wall_email.html.haml +++ b/app/views/notify/note_wall_email.html.haml @@ -1,22 +1,22 @@ -%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"} - %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"} +%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} + %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} %tr - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} - %td{:align => "left", :style => "padding: 20px 0 0;"} - %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{align: "left", style: "padding: 20px 0 0;"} + %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} New message on - = link_to "Project Wall", wall_project_url(@note.project, :anchor => "note_#{@note.id}") - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} + = link_to "Project Wall", wall_project_url(@note.project, anchor: "note_#{@note.id}") + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} %tr - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} - %td{:style => "padding: 15px 0 15px;", :valign => "top"} - %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} - %a{:href => "#", :style => "color: #0eb6ce; text-decoration: none;"} #{@note.author_name} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{style: "padding: 15px 0 15px;", valign: "top"} + %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} + %a{href: "#", style: "color: #0eb6ce; text-decoration: none;"} #{@note.author_name} left next message: %br - %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :width => "558"} + %table{border: "0", cellpadding: "0", cellspacing: "0", width: "558"} %tr - %td{:valign => "top"} - %div{ :style => "background:#f5f5f5; padding:20px;border:1px solid #ddd" } + %td{valign: "top"} + %div{ style: "background:#f5f5f5; padding:20px;border:1px solid #ddd" } = markdown(@note.note) - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} diff --git a/app/views/notify/note_wiki_email.html.haml b/app/views/notify/note_wiki_email.html.haml new file mode 100644 index 00000000000..d3840cdac06 --- /dev/null +++ b/app/views/notify/note_wiki_email.html.haml @@ -0,0 +1,23 @@ +%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} + %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} + %tr + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{align: "left", style: "padding: 20px 0 0;"} + %h2{style: "color:#646464 !important; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} + New comment for Wiki page + = link_to_gfm @wiki.title, project_issue_url(@wiki.project, @wiki, anchor: "note_#{@note.id}") + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %tr + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{style: "padding: 15px 0 15px;", valign: "top"} + %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} + %a{href: "#", style: "color: #0eb6ce; text-decoration: none;"} #{@note.author_name} + commented on Wiki page: + %br + %table{border: "0", cellpadding: "0", cellspacing: "0", width: "558"} + %tr + %td{valign: "top"} + %div{ style: "background:#f5f5f5; padding:20px;border:1px solid #ddd" } + = markdown(@note.note) + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + diff --git a/app/views/notify/reassigned_issue_email.html.haml b/app/views/notify/reassigned_issue_email.html.haml index 43579b274d3..c7896af3a54 100644 --- a/app/views/notify/reassigned_issue_email.html.haml +++ b/app/views/notify/reassigned_issue_email.html.haml @@ -1,16 +1,16 @@ -%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"} - %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"} +%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} + %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} %tr - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} - %td{:align => "left", :style => "padding: 20px 0 0;"} - %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} - Reassigned Issue - = link_to truncate(@issue.title, :length => 16), project_issue_url(@issue.project, @issue) - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{align: "left", style: "padding: 20px 0 0;"} + %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} + = "Reassigned Issue ##{@issue.id}" + = link_to_gfm truncate(@issue.title, length: 16), project_issue_url(@issue.project, @issue) + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} %tr - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} - %td{:style => "padding: 15px 0 15px;", :valign => "top"} - %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{style: "padding: 15px 0 15px;", valign: "top"} + %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} Assignee changed from #{@previous_assignee.name} to #{@issue.assignee_name} %td diff --git a/app/views/notify/reassigned_merge_request_email.html.haml b/app/views/notify/reassigned_merge_request_email.html.haml index 30b1f4fec42..e49b783635c 100644 --- a/app/views/notify/reassigned_merge_request_email.html.haml +++ b/app/views/notify/reassigned_merge_request_email.html.haml @@ -1,16 +1,16 @@ -%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"} - %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"} +%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} + %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} %tr - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} - %td{:align => "left", :style => "padding: 20px 0 0;"} - %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} - Reassigned Merge Request - = link_to truncate(@merge_request.title, :length => 16), project_merge_request_url(@merge_request.project, @merge_request) - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{align: "left", style: "padding: 20px 0 0;"} + %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} + = "Reassigned Merge Request !#{@merge_request.id}" + = link_to_gfm truncate(@merge_request.title, length: 16), project_merge_request_url(@merge_request.project, @merge_request) + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} %tr - %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} - %td{:style => "padding: 15px 0 15px;", :valign => "top"} - %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} + %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{style: "padding: 15px 0 15px;", valign: "top"} + %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} Assignee changed from #{@previous_assignee.name} to #{@merge_request.assignee_name} %td diff --git a/app/views/profile/design.html.haml b/app/views/profile/design.html.haml index ff6ae7f5778..d70483a25d8 100644 --- a/app/views/profile/design.html.haml +++ b/app/views/profile/design.html.haml @@ -1,37 +1,41 @@ -= form_for @user, :url => profile_update_path, :remote => true, :method => :put do |f| += form_for @user, url: profile_update_path, remote: true, method: :put do |f| %div - %h3 Application theme - %hr - .clearfix + %h3.page_title Application theme + %br + .themes_opts = label_tag do + .prev + = image_tag "gitlab_default.png" = f.radio_button :theme_id, 1 Default = label_tag do + .prev + = image_tag "gitlab_classic.png" = f.radio_button :theme_id, 2 Classic = label_tag do + .prev + = image_tag "gitlab_modern.png" = f.radio_button :theme_id, 3 Modern %br - %h3 Code review - %hr - .row - %label.span3{:for => "user_dark_scheme_false"} - .thumbnail - = image_tag "white.png", :width => 260, :class => "styled_image" - .caption - %h5 - = f.radio_button :dark_scheme, false - White code preview - %label.span3{:for => "user_dark_scheme_true"} - .thumbnail - = image_tag "dark.png", :width => 260, :class => "styled_image" - .caption - %h5 - = f.radio_button :dark_scheme, true - Dark code preview + .clearfix + + %h3.page_title Code review + %br + .themes_opts + = label_tag do + .prev + = image_tag "white.png" + = f.radio_button :dark_scheme, false + White code preview + = label_tag do + .prev + = image_tag "dark.png" + = f.radio_button :dark_scheme, true + Dark code preview :javascript $(function(){ diff --git a/app/views/profile/password.html.haml b/app/views/profile/password.html.haml index 1662f4d9c58..257dacb1ad3 100644 --- a/app/views/profile/password.html.haml +++ b/app/views/profile/password.html.haml @@ -1,6 +1,6 @@ %h3.page_title Password %hr -= form_for @user, :url => profile_password_path, :method => :put do |f| += form_for @user, url: profile_password_path, method: :put do |f| .data %p.slead After successful password update you will be redirected to login page where you should login with new password -if @user.errors.any? @@ -16,4 +16,4 @@ = f.label :password_confirmation .input= f.password_field :password_confirmation .actions - = f.submit 'Save', :class => "btn primary" + = f.submit 'Save', class: "btn primary" diff --git a/app/views/profile/show.html.haml b/app/views/profile/show.html.haml index b26890131bb..a7b6a18ad2d 100644 --- a/app/views/profile/show.html.haml +++ b/app/views/profile/show.html.haml @@ -1,5 +1,5 @@ .profile_avatar_holder - = image_tag gravatar_icon(@user.email, 90), :class => "styled_image" + = image_tag gravatar_icon(@user.email, 90), class: "styled_image" %h3.page_title = @user.name %br @@ -9,7 +9,7 @@ %hr -= form_for @user, :url => profile_update_path, :method => :put, :html => { :class => "edit_user form-horizontal" } do |f| += form_for @user, url: profile_update_path, method: :put, html: { class: "edit_user form-horizontal" } do |f| -if @user.errors.any? %div.alert-message.block-message.error %ul @@ -18,36 +18,37 @@ .row .span7 .control-group - = f.label :name, :class => "control-label" + = f.label :name, class: "control-label" .controls - = f.text_field :name, :class => "input-xlarge" + = f.text_field :name, class: "input-xlarge" %span.help-block Enter your name, so people you know can recognize you. .control-group - = f.label :email, :class => "control-label" + = f.label :email, class: "control-label" .controls - = f.text_field :email, :class => "input-xlarge" + = f.text_field :email, class: "input-xlarge" %span.help-block We also use email for avatar detection. %hr .control-group - = f.label :skype, :class => "control-label" - .controls= f.text_field :skype, :class => "input-xlarge" + = f.label :skype, class: "control-label" + .controls= f.text_field :skype, class: "input-xlarge" .control-group - = f.label :linkedin, :class => "control-label" - .controls= f.text_field :linkedin, :class => "input-xlarge" + = f.label :linkedin, class: "control-label" + .controls= f.text_field :linkedin, class: "input-xlarge" .control-group - = f.label :twitter, :class => "control-label" - .controls= f.text_field :twitter, :class => "input-xlarge" + = f.label :twitter, class: "control-label" + .controls= f.text_field :twitter, class: "input-xlarge" .control-group - = f.label :bio, :class => "control-label" + = f.label :bio, class: "control-label" .controls - = f.text_area :bio, :rows => 6, :class => "input-xlarge", :maxlength => 250 + = f.text_area :bio, rows: 6, class: "input-xlarge", maxlength: 250 %span.help-block Tell us about yourself in fewer than 250 characters. .span5.right - %p.alert.alert-info - %strong Tip: - You can change your avatar at gravatar.com + -unless Gitlab.config.disable_gravatar? + %p.alert.alert-info + %strong Tip: + You can change your avatar at gravatar.com %h4 Personal projects: @@ -56,14 +57,14 @@ of %span= current_user.projects_limit .progress - .bar{:style => "width: #{current_user.projects_limit_percent}%;"} + .bar{style: "width: #{current_user.projects_limit_percent}%;"} %h4 SSH public keys: %small.right %span= link_to current_user.keys.count, keys_path - = link_to "Add Public Key", new_key_path, :class => "btn small right" + = link_to "Add Public Key", new_key_path, class: "btn small right" .form-actions - = f.submit 'Save', :class => "btn-primary btn" + = f.submit 'Save', class: "btn-primary btn" diff --git a/app/views/profile/token.html.haml b/app/views/profile/token.html.haml index 3a0ec90bbef..6c870c364de 100644 --- a/app/views/profile/token.html.haml +++ b/app/views/profile/token.html.haml @@ -3,7 +3,7 @@ %span.cred.right keep it in secret! %hr -= form_for @user, :url => profile_reset_private_token_path, :method => :put do |f| += form_for @user, url: profile_reset_private_token_path, method: :put do |f| .data %p.slead Private token used to access application resources without authentication. @@ -11,13 +11,13 @@ It can be used for atom feed or API %p.cgray - if current_user.private_token - = text_field_tag "token", current_user.private_token, :class => "xxlarge large_text" + = text_field_tag "token", current_user.private_token, class: "xxlarge large_text" - else You don`t have one yet. Click generate to fix it. .actions - if current_user.private_token - = f.submit 'Reset', :confirm => "Are you sure?", :class => "btn" + = f.submit 'Reset', confirm: "Are you sure?", class: "btn" - else - = f.submit 'Generate', :class => "btn primary" + = f.submit 'Generate', class: "btn primary" diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index 6bc48df9183..ce66b2cf930 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -1,4 +1,4 @@ -= form_for(@project, :remote => true) do |f| += form_for(@project, remote: true) do |f| - if @project.errors.any? .alert-message.block-message.error %ul @@ -8,7 +8,7 @@ = f.label :name do Project name is .input - = f.text_field :name, :placeholder => "Example Project", :class => "xxlarge" + = f.text_field :name, placeholder: "Example Project", class: "xxlarge" %h5.page_title .alert.alert-info @@ -19,19 +19,19 @@ .input .input-prepend %strong - = text_field_tag :ppath, @project.path_to_repo, :class => "xlarge", :disabled => true + = text_field_tag :ppath, @project.path_to_repo, class: "xlarge", disabled: true .clearfix = f.label :code do URL .input .input-prepend %span.add-on= web_app_url - = f.text_field :code, :placeholder => "example" + = f.text_field :code, placeholder: "example" - unless @project.new_record? || @project.heads.empty? .clearfix = f.label :default_branch, "Default Branch" - .input= f.select(:default_branch, @project.heads.map(&:name), {}, :style => "width:210px;") + .input= f.select(:default_branch, @project.heads.map(&:name), {}, style: "width:210px;") - unless @project.new_record? .alert.alert-info @@ -56,8 +56,8 @@ %br .actions - = f.submit 'Save', :class => "btn primary" - = link_to 'Cancel', @project, :class => "btn" + = f.submit 'Save', class: "btn primary" + = link_to 'Cancel', @project, class: "btn" - unless @project.new_record? .right - = link_to 'Remove', @project, :confirm => 'Are you sure?', :method => :delete, :class => "btn danger" + = link_to 'Remove', @project, confirm: 'Are you sure?', method: :delete, class: "btn danger" diff --git a/app/views/projects/_new_form.html.haml b/app/views/projects/_new_form.html.haml index 9f3bfa86b91..5104df83a2c 100644 --- a/app/views/projects/_new_form.html.haml +++ b/app/views/projects/_new_form.html.haml @@ -1,4 +1,4 @@ -= form_for(@project, :remote => true) do |f| += form_for(@project, remote: true) do |f| - if @project.errors.any? .alert-message.block-message.error %span= @project.errors.full_messages.first @@ -6,8 +6,8 @@ = f.label :name do Project name is .input - = f.text_field :name, :placeholder => "Example Project", :class => "xxlarge" - = f.submit 'Create project', :class => "btn primary" + = f.text_field :name, placeholder: "Example Project", class: "xxlarge" + = f.submit 'Create project', class: "btn primary" %hr .alert.alert-info @@ -18,7 +18,7 @@ .input .input-prepend %span.add-on= Gitlab.config.ssh_path - = f.text_field :path, :placeholder => "example_project", :disabled => !@project.new_record? + = f.text_field :path, placeholder: "example_project", disabled: !@project.new_record? %span.add-on= ".git" .clearfix = f.label :code do @@ -26,4 +26,4 @@ .input .input-prepend %span.add-on= web_app_url - = f.text_field :code, :placeholder => "example" + = f.text_field :code, placeholder: "example" diff --git a/app/views/projects/_project_head.html.haml b/app/views/projects/_project_head.html.haml index f3ac3c27ccf..ba64ee7f996 100644 --- a/app/views/projects/_project_head.html.haml +++ b/app/views/projects/_project_head.html.haml @@ -1,29 +1,29 @@ %ul.nav.nav-tabs - %li{ :class => "#{'active' if current_page?(project_path(@project)) }" } - = link_to project_path(@project), :class => "activities-tab tab" do + %li{ class: "#{'active' if current_page?(project_path(@project)) }" } + = link_to project_path(@project), class: "activities-tab tab" do %i.icon-home Show - %li{ :class => " #{'active' if (controller.controller_name == "team_members") || current_page?(team_project_path(@project)) }" } - = link_to team_project_path(@project), :class => "team-tab tab" do + %li{ class: " #{'active' if (controller.controller_name == "team_members") || current_page?(team_project_path(@project)) }" } + = link_to team_project_path(@project), class: "team-tab tab" do %i.icon-user Team - %li{ :class => "#{'active' if current_page?(files_project_path(@project)) }" } - = link_to files_project_path(@project), :class => "files-tab tab " do + %li{ class: "#{'active' if current_page?(files_project_path(@project)) }" } + = link_to files_project_path(@project), class: "files-tab tab " do Attachments - %li{ :class => " #{'active' if (controller.controller_name == "snippets") }" } - = link_to project_snippets_path(@project), :class => "snippets-tab tab" do + %li{ class: " #{'active' if (controller.controller_name == "snippets") }" } + = link_to project_snippets_path(@project), class: "snippets-tab tab" do Snippets - if can? current_user, :admin_project, @project - %li.right{:class => "#{'active' if controller.controller_name == "deploy_keys"}"} + %li.right{class: "#{'active' if controller.controller_name == "deploy_keys"}"} = link_to project_deploy_keys_path(@project) do %span Deploy Keys - %li.right{:class => "#{'active' if controller.controller_name == "hooks" }"} + %li.right{class: "#{'active' if controller.controller_name == "hooks" }"} = link_to project_hooks_path(@project) do %span Hooks - %li.right{ :class => "#{'active' if current_page?(edit_project_path(@project)) }" } - = link_to edit_project_path(@project), :class => "stat-tab tab " do + %li.right{ class: "#{'active' if current_page?(edit_project_path(@project)) }" } + = link_to edit_project_path(@project), class: "stat-tab tab " do %i.icon-edit Edit diff --git a/app/views/projects/_refs.html.haml b/app/views/projects/_refs.html.haml index af15fbdfb3d..804b852340e 100644 --- a/app/views/projects/_refs.html.haml +++ b/app/views/projects/_refs.html.haml @@ -1,5 +1,5 @@ -= form_tag switch_project_refs_path(@project), :method => :get, :class => "project-refs-form" do - = select_tag "ref", grouped_options_refs, :onchange => "this.form.submit();", :class => "project-refs-select" += form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form" do + = select_tag "ref", grouped_options_refs, onchange: "this.form.submit();", class: "project-refs-select" = hidden_field_tag :destination, destination :javascript diff --git a/app/views/projects/_show.html.haml b/app/views/projects/_show.html.haml index c6755fa730a..e8a5b00dd0e 100644 --- a/app/views/projects/_show.html.haml +++ b/app/views/projects/_show.html.haml @@ -2,9 +2,9 @@ = @project.name %br %div - %a.btn.info{:href => tree_project_ref_path(@project, @project.root_ref)} Browse code + %a.btn.info{href: tree_project_ref_path(@project, @project.root_ref)} Browse code - %a.btn{:href => project_commits_path(@project)} Commits + %a.btn{href: project_commits_path(@project)} Commits %strong.right = link_to project_path(@project) do Switch to project → @@ -13,7 +13,7 @@ .input .input-prepend %span.add-on git clone - = text_field_tag :project_clone, @project.url_to_repo, :class => "xlarge one_click_select git_clone_url" + = text_field_tag :project_clone, @project.url_to_repo, class: "xlarge one_click_select git_clone_url" = simple_format @project.description - unless @events.blank? diff --git a/app/views/projects/_team.html.haml b/app/views/projects/_team.html.haml index 5839346052a..175aea27ed4 100644 --- a/app/views/projects/_team.html.haml +++ b/app/views/projects/_team.html.haml @@ -5,7 +5,7 @@ %th Permissions %tbody - @project.users_projects.each do |up| - = render(:partial => 'team_members/show', :locals => {:member => up}) + = render(partial: 'team_members/show', locals: {member: up}) :javascript diff --git a/app/views/projects/create.js.haml b/app/views/projects/create.js.haml index eeefc1729c8..2f6264a15af 100644 --- a/app/views/projects/create.js.haml +++ b/app/views/projects/create.js.haml @@ -1,6 +1,6 @@ - if @project.saved? :plain - location.href = "#{project_path(@project, :notice => 'Project was successfully created.')}"; + location.href = "#{project_path(@project, notice: 'Project was successfully created.')}"; - else - if @project.git_error? location.href = "#{errors_githost_path}"; diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml index eef113e002b..907d5ef4666 100644 --- a/app/views/projects/empty.html.haml +++ b/app/views/projects/empty.html.haml @@ -1,47 +1,30 @@ -- if current_user.require_ssh_key? - .alert-message.block-message.error - %ul - %li You have no ssh keys added to your profile. - %li You wont be able to pull/push repository. - %li Visit profile → keys and add public key of every machine you want to use for work with gitlabhq. - -.alert-message.block-message.error - %ul.unstyled.alert_holder - %li You should push repository to proceed. - %li After push you will be able to browse code, commits etc. - -- bash_lexer = Pygments::Lexer[:bash] += render 'shared/no_ssh' %div.git-empty - %h3 Git global setup: - - setup_str = ["git config --global user.name \"#{current_user.name}\"", - "git config --global user.email \"#{current_user.email}\""].join("\n") - = preserve do - = raw bash_lexer.highlight(setup_str, :lexer => 'bash', :options => {:encoding => 'utf-8'}) - - %br - %br - %h3 Create Repository - - repo_setup_str = ["mkdir #{@project.path}", - "cd #{@project.path}", - "git init", - "touch README", - "git add README", - "git commit -m 'first commit'", - "git remote add origin #{@project.url_to_repo}", - "git push -u origin master"].join("\n") + %h4 Git global setup: + %pre.dark + = preserve do + git config --global user.name "#{current_user.name}" + git config --global user.email "#{current_user.email}" - = preserve do - = raw bash_lexer.highlight(repo_setup_str) + %h4.prepend-top-20 Create Repository + %pre.dark + = preserve do + mkdir #{@project.path} + cd #{@project.path} + git init + touch README + git add README + git commit -m 'first commit' + git remote add origin #{@project.url_to_repo} + git push -u origin master - %br - %br - %h3 Existing Git Repo? - - exist_repo_setup_str = ["cd existing_git_repo", - "git remote add origin #{@project.url_to_repo}", - "git push -u origin master"].join("\n") - = preserve do - = raw bash_lexer.highlight(exist_repo_setup_str) + %h4.prepend-top-20 Existing Git Repo? + %pre.dark + = preserve do + cd existing_git_repo + git remote add origin #{@project.url_to_repo} + git push -u origin master - if can? current_user, :admin_project, @project - .alert-message.block-message.error.prepend-top-20 - = link_to 'Remove project', @project, :confirm => 'Are you sure?', :method => :delete, :class => "btn danger" + .prepend-top-20 + = link_to 'Remove project', @project, confirm: 'Are you sure?', method: :delete, class: "btn danger right" diff --git a/app/views/projects/files.html.haml b/app/views/projects/files.html.haml index d171b0d09a1..68d51df0b56 100644 --- a/app/views/projects/files.html.haml +++ b/app/views/projects/files.html.haml @@ -4,8 +4,8 @@ - @notes.each do |note| %tr %td - %a{:href => note.attachment.url} - = image_tag gravatar_icon(note.author_email), :class => "left", :width => 16 + %a{href: note.attachment.url} + = image_tag gravatar_icon(note.author_email), class: "left", width: 16 = note.attachment_identifier %td @@ -14,6 +14,6 @@ ago - else .alert-message.block-message - %p All files attached to project wall, issues etc will be displayed here + %span All files attached to project wall, issues etc will be displayed here diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 0d119bd1d96..703e558ae41 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -6,7 +6,7 @@ %div.ajax_loader.hide %center %div.padded= image_tag "ajax_loader.gif" - %h3.prepend-top Creating project & repository. Please wait for few minutes + %h3.prepend-top Creating project & repository. Please wait a few minutes :javascript $(function(){ new Projects(); }); diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 7c5b11e4be0..ebd2c8e4495 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -7,23 +7,23 @@ .input-prepend.project_clone_holder %span.add-on git clone - = link_to "SSH", "#", :class => "btn small active", :"data-clone" => @project.ssh_url_to_repo - = link_to "HTTP", "#", :class => "btn small", :"data-clone" => @project.http_url_to_repo - = text_field_tag :project_clone, @project.url_to_repo, :class => "one_click_select span5" + = link_to "SSH", "#", class: "btn small active", :"data-clone" => @project.ssh_url_to_repo + = link_to "HTTP", "#", class: "btn small", :"data-clone" => @project.http_url_to_repo + = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select span5" .span4.right .right - if can? current_user, :download_code, @project - = link_to archive_project_repository_path(@project), :class => "btn small grouped" do + = link_to archive_project_repository_path(@project), class: "btn small grouped" do %i.icon-download-alt Download - if @project.merge_requests_enabled && can?(current_user, :write_merge_request, @project) - = link_to new_project_merge_request_path(@project), :title => "New Merge Request", :class => "btn small grouped" do + = link_to new_project_merge_request_path(@project), title: "New Merge Request", class: "btn small grouped" do Merge Request - if @project.issues_enabled && can?(current_user, :write_issue, @project) - = link_to new_project_issue_path(@project), :title => "New Issue", :class => "btn small grouped" do + = link_to new_project_issue_path(@project), title: "New Issue", class: "btn small grouped" do Issue -= render "events/event_last_push", :event => @last_push += render "events/event_last_push", event: @last_push .content_list= render @events :javascript diff --git a/app/views/projects/team.html.haml b/app/views/projects/team.html.haml index 90be041479d..e8a825c741e 100644 --- a/app/views/projects/team.html.haml +++ b/app/views/projects/team.html.haml @@ -5,11 +5,11 @@ - if can? current_user, :admin_team_member, @project %p.slead - = link_to new_project_team_member_path(@project), :class => "btn small right", :title => "New Team Member" do + = link_to new_project_team_member_path(@project), class: "btn small right", title: "New Team Member" do New Team Member Read more about project permissions - %strong= link_to "here", help_permissions_path, :class => "vlink" + %strong= link_to "here", help_permissions_path, class: "vlink" -= render :partial => "team", :locals => {:project => @project} += render partial: "team", locals: {project: @project} diff --git a/app/views/projects/tree.js.haml b/app/views/projects/tree.js.haml index eb08adb1ddd..ba5d53c16a2 100644 --- a/app/views/projects/tree.js.haml +++ b/app/views/projects/tree.js.haml @@ -1,5 +1,5 @@ :plain $("#tree-holder table").hide("slide", { direction: "left" }, 150, function(){ - $("#tree-holder").html("#{escape_javascript(render(:partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree}))}"); + $("#tree-holder").html("#{escape_javascript(render(partial: "tree", locals: {repo: @repo, commit: @commit, tree: @tree}))}"); $("#tree-holder table").show("slide", { direction: "right" }, 150); }); diff --git a/app/views/projects/update.js.haml b/app/views/projects/update.js.haml index ee0d36996b5..a961dc39791 100644 --- a/app/views/projects/update.js.haml +++ b/app/views/projects/update.js.haml @@ -1,6 +1,6 @@ - if @project.valid? :plain - location.href = "#{edit_project_path(@project, :notice => 'Project was successfully updated.')}"; + location.href = "#{edit_project_path(@project, notice: 'Project was successfully updated.')}"; - else :plain $('.project_edit_holder').show(); diff --git a/app/views/projects/wall.html.haml b/app/views/projects/wall.html.haml index bd538e8f971..97765d7ac88 100644 --- a/app/views/projects/wall.html.haml +++ b/app/views/projects/wall.html.haml @@ -1,2 +1,2 @@ %div.wall_page - = render "notes/notes", :tid => nil, :tt => "wall" + = render "notes/notes", tid: nil, tt: "wall" diff --git a/app/views/protected_branches/index.html.haml b/app/views/protected_branches/index.html.haml index bd1e9cebb1a..2b93b0a83db 100644 --- a/app/views/protected_branches/index.html.haml +++ b/app/views/protected_branches/index.html.haml @@ -1,12 +1,12 @@ = render "repositories/branches_head" .alert - %p Protected branches designed to prevent push for all except #{link_to "masters", help_permissions_path, :class => "vlink"}. + %p Protected branches designed to prevent push for all except #{link_to "masters", help_permissions_path, class: "vlink"}. %p This ability allows: %ul %li keep stable branches secured %li forced code review before merge to protected branches - %p Read more about project permissions #{link_to "here", help_permissions_path, :class => "vlink"} + %p Read more about project permissions #{link_to "here", help_permissions_path, class: "vlink"} - if can? current_user, :admin_project, @project = form_for [@project, @protected_branch] do |f| @@ -19,9 +19,9 @@ .entry.clearfix = f.label :name, "Branch" .span3 - = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , { :include_blank => "-- Select branch" }, { :class => "span3" }) + = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , { include_blank: "-- Select branch" }, { class: "span3" }) - = f.submit 'Protect', :class => "primary btn" + = f.submit 'Protect', class: "primary btn" - unless @branches.empty? %table.admin-table @@ -34,18 +34,18 @@ - @branches.each do |branch| %tr %td - = link_to project_commits_path(@project, :ref => branch.name) do + = link_to project_commits_path(@project, ref: branch.name) do %strong= branch.name - if branch.name == @project.root_ref %span.label default %td - = link_to project_commits_path(@project, branch.commit.id) do - = truncate branch.commit.id.to_s, :length => 10 + = link_to project_commit_path(@project, branch.commit.id) do + = truncate branch.commit.id.to_s, length: 10 = time_ago_in_words(branch.commit.committed_date) ago %td - if can? current_user, :admin_project, @project - = link_to 'Unprotect', [@project, branch], :confirm => 'Are you sure?', :method => :delete, :class => "danger btn small" + = link_to 'Unprotect', [@project, branch], confirm: 'Are you sure?', method: :delete, class: "danger btn small" :javascript $('select#protected_branch_name').chosen(); diff --git a/app/views/refs/_head.html.haml b/app/views/refs/_head.html.haml index 16a0cddfa24..8825493a0ec 100644 --- a/app/views/refs/_head.html.haml +++ b/app/views/refs/_head.html.haml @@ -1,10 +1,10 @@ %ul.nav.nav-tabs %li - = form_tag switch_project_refs_path(@project), :method => :get, :class => "project-refs-form", :remote => true do - = select_tag "ref", grouped_options_refs, :onchange => "$(this.form).trigger('submit');", :class => "project-refs-select" + = form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form", remote: true do + = select_tag "ref", grouped_options_refs, onchange: "$(this.form).trigger('submit');", class: "project-refs-select" = hidden_field_tag :destination, "tree" = hidden_field_tag :path, params[:path] - %li{:class => "#{'active' if (controller.controller_name == "refs") }"} + %li{class: "#{'active' if (controller.controller_name == "refs") }"} = link_to tree_project_ref_path(@project, @ref) do Source diff --git a/app/views/refs/_submodule_item.html.haml b/app/views/refs/_submodule_item.html.haml index 6db49310a08..6b9f5877028 100644 --- a/app/views/refs/_submodule_item.html.haml +++ b/app/views/refs/_submodule_item.html.haml @@ -1,13 +1,13 @@ - url = content.url(@ref) rescue nil - name = content.basename - return unless url -%tr{ :class => "tree-item", :url => url } +%tr{ class: "tree-item", url: url } %td.tree-item-file-name = image_tag "submodule.png" - %strong= truncate(name, :length => 40) + %strong= truncate(name, length: 40) %td %code= content.id[0..10] %td - = link_to truncate(url, :length => 40), url + = link_to truncate(url, length: 40), url diff --git a/app/views/refs/_tree.html.haml b/app/views/refs/_tree.html.haml index ba0bd69116b..c231c40735c 100644 --- a/app/views/refs/_tree.html.haml +++ b/app/views/refs/_tree.html.haml @@ -1,7 +1,7 @@ %ul.breadcrumb %li %span.arrow - = link_to tree_project_ref_path(@project, @ref, :path => nil), :remote => true do + = link_to tree_project_ref_path(@project, @ref, path: nil), remote: true do = @project.name - tree.breadcrumbs(6) do |link| \/ @@ -10,32 +10,32 @@ %div.tree_progress #tree-content-holder - if tree.is_blob? - = render :partial => "refs/tree_file", :locals => { :name => tree.name, :content => tree.data, :file => tree } + = render partial: "refs/tree_file", locals: { name: tree.name, content: tree.data, file: tree } - else - contents = tree.contents - %table#tree-slider.bordered-table.table{:class => "table_#{@hex_path}" } + %table#tree-slider.bordered-table.table{class: "table_#{@hex_path}" } %thead %th Name %th Last Update %th Last commit - = link_to "History", tree.history_path, :class => "right" + = link_to "History", tree.history_path, class: "right" - if tree.up_dir? - %tr{ :class => "tree-item", :url => tree.up_dir_path } + %tr{ class: "tree-item", url: tree.up_dir_path } %td.tree-item-file-name = image_tag "file_empty.png" - = link_to "..", tree.up_dir_path, :remote => :true + = link_to "..", tree.up_dir_path, remote: :true %td %td - index = 0 - contents.select{ |i| i.is_a?(Grit::Tree)}.each do |content| - = render :partial => "refs/tree_item", :locals => { :content => content, :index => (index += 1) } + = render partial: "refs/tree_item", locals: { content: content, index: (index += 1) } - contents.select{ |i| i.is_a?(Grit::Blob)}.each do |content| - = render :partial => "refs/tree_item", :locals => { :content => content, :index => (index += 1) } + = render partial: "refs/tree_item", locals: { content: content, index: (index += 1) } - contents.select{ |i| i.is_a?(Grit::Submodule)}.each do |content| - = render :partial => "refs/submodule_item", :locals => { :content => content, :index => (index += 1) } + = render partial: "refs/submodule_item", locals: { content: content, index: (index += 1) } - if content = contents.select{ |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i }.first .file_holder#README @@ -51,8 +51,6 @@ :javascript $(function(){ - $('select#branch').selectmenu({style:'popup', width:200}); - $('select#tag').selectmenu({style:'popup', width:200}); $('.project-refs-select').chosen(); history.pushState({ path: this.path }, '', "#{@history_path}"); diff --git a/app/views/refs/_tree_commit.html.haml b/app/views/refs/_tree_commit.html.haml index 1f2524a4c3a..1bcf1a7ea1d 100644 --- a/app/views/refs/_tree_commit.html.haml +++ b/app/views/refs/_tree_commit.html.haml @@ -1,3 +1,3 @@ - if tm - %strong= link_to "[#{tm.user_name}]", project_team_member_path(@project, tm) -= link_to truncate(content_commit.safe_message, :length => tm ? 30 : 50), project_commit_path(@project, content_commit.id), :class => "tree-commit-link" + = link_to "[#{tm.user_name}]", project_team_member_path(@project, tm) += link_to_gfm truncate(content_commit.title, length: tm ? 30 : 50), project_commit_path(@project, content_commit.id), class: "tree-commit-link" diff --git a/app/views/refs/_tree_file.html.haml b/app/views/refs/_tree_file.html.haml index d45a03df8aa..b5ed61bb45a 100644 --- a/app/views/refs/_tree_file.html.haml +++ b/app/views/refs/_tree_file.html.haml @@ -5,9 +5,9 @@ = name %small #{file.mode} %span.options - = link_to "raw", blob_project_ref_path(@project, @ref, :path => params[:path]), :class => "btn very_small", :target => "_blank" - = link_to "history", project_commits_path(@project, :path => params[:path], :ref => @ref), :class => "btn very_small" - = link_to "blame", blame_file_project_ref_path(@project, @ref, :path => params[:path]), :class => "btn very_small" + = link_to "raw", blob_project_ref_path(@project, @ref, path: params[:path]), class: "btn very_small", target: "_blank" + = link_to "history", project_commits_path(@project, path: params[:path], ref: @ref), class: "btn very_small" + = link_to "blame", blame_file_project_ref_path(@project, @ref, path: params[:path]), class: "btn very_small" - if file.text? - if name =~ /\.(md|markdown)$/i .file_content.wiki @@ -16,7 +16,7 @@ - else .file_content.code - unless file.empty? - %div{:class => current_user.dark_scheme ? "black" : "white"} + %div{class: current_user.dark_scheme ? "black" : "white"} = preserve do = raw file.colorize(options: { linenos: 'True'}) - else @@ -24,14 +24,14 @@ - elsif file.image? .file_content.image_file - %img{ :src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} + %img{ src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} - else .file_content.blob_file %center - = link_to blob_project_ref_path(@project, @ref, :path => params[:path]) do + = link_to blob_project_ref_path(@project, @ref, path: params[:path]) do %div.padded %br - = image_tag "download.png", :width => 64 + = image_tag "download.png", width: 64 %h3 Download (#{file.mb_size}) diff --git a/app/views/refs/_tree_item.html.haml b/app/views/refs/_tree_item.html.haml index 4ce16b22ddd..2e6bbf6221b 100644 --- a/app/views/refs/_tree_item.html.haml +++ b/app/views/refs/_tree_item.html.haml @@ -1,11 +1,11 @@ - file = tree_full_path(content) -%tr{ :class => "tree-item #{tree_hex_class(content)}", :url => tree_file_project_ref_path(@project, @ref, file) } +%tr{ class: "tree-item #{tree_hex_class(content)}", url: tree_file_project_ref_path(@project, @ref, file) } %td.tree-item-file-name = tree_icon(content) - = link_to truncate(content.name, :length => 40), tree_file_project_ref_path(@project, @ref || @commit.id, file), :remote => :true + = link_to truncate(content.name, length: 40), tree_file_project_ref_path(@project, @ref || @commit.id, file), remote: :true %td.tree_time_ago.cgray - if index == 1 %span.log_loading Loading commit data.. - = image_tag "ajax_loader_tree.gif", :width => 14 + = image_tag "ajax_loader_tree.gif", width: 14 %td.tree_commit diff --git a/app/views/refs/blame.html.haml b/app/views/refs/blame.html.haml index 6a86b91fe74..34478d4b491 100644 --- a/app/views/refs/blame.html.haml +++ b/app/views/refs/blame.html.haml @@ -4,7 +4,7 @@ %ul.breadcrumb %li %span.arrow - = link_to tree_project_ref_path(@project, @ref, :path => nil) do + = link_to tree_project_ref_path(@project, @ref, path: nil) do = @project.name - @tree.breadcrumbs(6) do |link| \/ @@ -18,22 +18,22 @@ = @tree.name %small blame %span.options - = link_to "raw", blob_project_ref_path(@project, @ref, :path => params[:path]), :class => "btn very_small", :target => "_blank" - = link_to "history", project_commits_path(@project, :path => params[:path], :ref => @ref), :class => "btn very_small" - = link_to "source", tree_file_project_ref_path(@project, @ref, :path => params[:path]), :class => "btn very_small" + = link_to "raw", blob_project_ref_path(@project, @ref, path: params[:path]), class: "btn very_small", target: "_blank" + = link_to "history", project_commits_path(@project, path: params[:path], ref: @ref), class: "btn very_small" + = link_to "source", tree_file_project_ref_path(@project, @ref, path: params[:path]), class: "btn very_small" .file_content.blame %table - @blame.each do |commit, lines| - commit = Commit.new(commit) + - commit = CommitDecorator.decorate(commit) %tr %td.author = image_tag gravatar_icon(commit.author_email, 16) = commit.author_name %td.blame_commit - = link_to project_commit_path(@project, :id => commit.id) do - %code= commit.id.to_s[0..10] - %span.row_title= truncate(commit.safe_message, :length => 30) rescue "--broken encoding" + %code= link_to commit.short_id, project_commit_path(@project, id: commit.id) + = link_to_gfm truncate(commit.title, length: 30), project_commit_path(@project, id: commit.id), class: "row_title" rescue "--broken encoding" %td.lines = preserve do %pre diff --git a/app/views/refs/logs_tree.js.haml b/app/views/refs/logs_tree.js.haml index 402f5aa72bc..61ccbaee1fe 100644 --- a/app/views/refs/logs_tree.js.haml +++ b/app/views/refs/logs_tree.js.haml @@ -6,4 +6,4 @@ :plain var row = $("table.table_#{@hex_path} tr.file_#{hexdigest(file_name)}"); row.find("td.tree_time_ago").html('#{escape_javascript(time_ago_in_words(content_commit.committed_date))} ago'); - row.find("td.tree_commit").html('#{escape_javascript(render("tree_commit", :tm => tm, :content_commit => content_commit))}'); + row.find("td.tree_commit").html('#{escape_javascript(render("tree_commit", tm: tm, content_commit: content_commit))}'); diff --git a/app/views/refs/tree.html.haml b/app/views/refs/tree.html.haml index b48f7f91782..181be6426d4 100644 --- a/app/views/refs/tree.html.haml +++ b/app/views/refs/tree.html.haml @@ -1,5 +1,5 @@ = render "head" -#tree-holder= render :partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree} +#tree-holder= render partial: "tree", locals: {repo: @repo, commit: @commit, tree: @tree} :javascript $(function() { diff --git a/app/views/refs/tree.js.haml b/app/views/refs/tree.js.haml index 9cf55057a6a..2eccf8c19a6 100644 --- a/app/views/refs/tree.js.haml +++ b/app/views/refs/tree.js.haml @@ -1,6 +1,6 @@ :plain // Load Files list - $("#tree-holder").html("#{escape_javascript(render(:partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree}))}"); + $("#tree-holder").html("#{escape_javascript(render(partial: "tree", locals: {repo: @repo, commit: @commit, tree: @tree}))}"); $("#tree-content-holder").show("slide", { direction: "right" }, 150); $('.project-refs-form #path').val("#{params[:path]}"); diff --git a/app/views/repositories/_branch.html.haml b/app/views/repositories/_branch.html.haml index 4742b92bd74..cf8558ec33e 100644 --- a/app/views/repositories/_branch.html.haml +++ b/app/views/repositories/_branch.html.haml @@ -1,20 +1,21 @@ +- commit = Commit.new(branch.commit) +- commit = CommitDecorator.decorate(commit) %tr %td - = link_to project_commits_path(@project, :ref => branch.name) do - %strong= branch.name + = link_to project_commits_path(@project, ref: branch.name) do + %strong= truncate(branch.name, length: 60) - if branch.name == @project.root_ref %span.label default %td - = link_to project_commit_path(@project, :id => branch.commit.id) do - %code= branch.commit.id.to_s[0..10] + = link_to project_commit_path(@project, id: commit.id) do + %code= commit.short_id - = image_tag gravatar_icon(Commit.new(branch.commit).author_email), :class => "", :width => 16 - = truncate(Commit.new(branch.commit).safe_message, :length => 40) - %td + = image_tag gravatar_icon(commit.author_email), class: "", width: 16 + = gfm truncate(commit.title, length: 40) %span.update-author.right - = time_ago_in_words(branch.commit.committed_date) + = time_ago_in_words(commit.committed_date) ago %td - if can? current_user, :download_code, @project - = link_to "Download", archive_project_repository_path(@project, :ref => branch.name), :class => "visible_link download_repo_link" + = link_to "Download", archive_project_repository_path(@project, ref: branch.name), class: "visible_link download_repo_link" diff --git a/app/views/repositories/_branches_head.html.haml b/app/views/repositories/_branches_head.html.haml index 0c94f298270..6afff627b94 100644 --- a/app/views/repositories/_branches_head.html.haml +++ b/app/views/repositories/_branches_head.html.haml @@ -1,11 +1,11 @@ = render "commits/head" %ul.nav.nav-pills - %li{:class => ("active" if current_page?(project_repository_path(@project)))} + %li{class: ("active" if current_page?(project_repository_path(@project)))} = link_to project_repository_path(@project) do Recent - %li{:class => ("active" if current_page?(project_protected_branches_path(@project)))} + %li{class: ("active" if current_page?(project_protected_branches_path(@project)))} = link_to project_protected_branches_path(@project) do Protected - %li{:class => ("active" if current_page?(branches_project_repository_path(@project)))} + %li{class: ("active" if current_page?(branches_project_repository_path(@project)))} = link_to branches_project_repository_path(@project) do All diff --git a/app/views/repositories/_feed.html.haml b/app/views/repositories/_feed.html.haml index 0734327233e..ac4eb483945 100644 --- a/app/views/repositories/_feed.html.haml +++ b/app/views/repositories/_feed.html.haml @@ -1,7 +1,8 @@ - commit = update +- commit = CommitDecorator.new(commit) %tr %td - = link_to project_commits_path(@project, :ref => commit.head.name) do + = link_to project_commits_path(@project, ref: commit.head.name) do %strong = commit.head.name - if commit.head.name == @project.root_ref @@ -10,9 +11,9 @@ %td %div = link_to project_commits_path(@project, commit.id) do - %code= commit.id.to_s[0..10] - = image_tag gravatar_icon(commit.author_email), :class => "", :width => 16 - = truncate(commit.safe_message, :length => 40) + %code= commit.short_id + = image_tag gravatar_icon(commit.author_email), class: "", width: 16 + = gfm truncate(commit.title, length: 40) %td %span.right.cgray = time_ago_in_words(commit.committed_date) diff --git a/app/views/repositories/branches.html.haml b/app/views/repositories/branches.html.haml index 52c0bf8e618..45004bdff43 100644 --- a/app/views/repositories/branches.html.haml +++ b/app/views/repositories/branches.html.haml @@ -5,9 +5,8 @@ %tr %th Name %th Last commit - %th Updated at %th %tbody - @branches.each do |branch| - = render "repositories/branch", :branch => branch + = render "repositories/branch", branch: branch diff --git a/app/views/repositories/show.html.haml b/app/views/repositories/show.html.haml index ceb971a4e17..a09cdd6212b 100644 --- a/app/views/repositories/show.html.haml +++ b/app/views/repositories/show.html.haml @@ -5,8 +5,7 @@ %tr %th Name %th Last commit - %th Updated at %th - @activities.each do |update| - = render "repositories/branch", :branch => update.head + = render "repositories/branch", branch: update.head diff --git a/app/views/repositories/tags.html.haml b/app/views/repositories/tags.html.haml index 5e5cca31d8f..7fc2c3bfd2f 100644 --- a/app/views/repositories/tags.html.haml +++ b/app/views/repositories/tags.html.haml @@ -9,14 +9,15 @@ %th - @tags.each do |tag| - commit = Commit.new(tag.commit) + - commit = CommitDecorator.decorate(commit) %tr %td - %strong= link_to tag.name, project_commits_path(@project, :ref => tag.name), :class => "" + %strong= link_to tag.name, project_commits_path(@project, ref: tag.name), class: "" %td = link_to project_commit_path(@project, commit.id) do - %code= commit.id.to_s[0..10] - = image_tag gravatar_icon(commit.author_email), :class => "", :width => 16 - = truncate(commit.safe_message, :length => 40) + %code= commit.short_id + = image_tag gravatar_icon(commit.author_email), class: "", width: 16 + = gfm truncate(commit.title, length: 40) %td %span.update-author.right = time_ago_in_words(commit.committed_date) @@ -24,7 +25,7 @@ %td - if can? current_user, :download_code, @project - = link_to "Download", archive_project_repository_path(@project, :ref => tag.name), :class => "visible_link download_repo_link" + = link_to "Download", archive_project_repository_path(@project, ref: tag.name), class: "visible_link download_repo_link" - else %h3 No tags diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml index b93a03af2f1..9a0b4789588 100644 --- a/app/views/search/show.html.haml +++ b/app/views/search/show.html.haml @@ -1,10 +1,10 @@ -= form_tag search_path, :method => :get do |f| += form_tag search_path, method: :get, class: 'form-inline' do |f| .padded = label_tag :search do %strong Looking for .input - = text_field_tag :search, params[:search], :placeholder => "issue 143", :class => "input-xxlarge", :id => "dashboard_search" - = submit_tag 'Search', :class => "btn btn-primary" + = text_field_tag :search, params[:search], placeholder: "issue 143", class: "input-xxlarge", id: "dashboard_search" + = submit_tag 'Search', class: "btn btn-primary" - if params[:search].present? %br %h3 @@ -41,7 +41,7 @@ = link_to [merge_request.project, merge_request] do %span.badge.badge-info ##{merge_request.id} – - %strong.term= truncate merge_request.title, :length => 50 + %strong.term= truncate merge_request.title, length: 50 %strong.right %span.label= merge_request.project.name - if @merge_requests.blank? @@ -59,7 +59,7 @@ = link_to [issue.project, issue] do %span.badge.badge-info ##{issue.id} – - %strong.term= truncate issue.title, :length => 40 + %strong.term= truncate issue.title, length: 40 %strong.right %span.label= issue.project.name - if @issues.blank? diff --git a/app/views/shared/_no_ssh.html.haml b/app/views/shared/_no_ssh.html.haml new file mode 100644 index 00000000000..b6ab666bc5d --- /dev/null +++ b/app/views/shared/_no_ssh.html.haml @@ -0,0 +1,8 @@ +- if current_user.require_ssh_key? + %h6.error_message + %span + You wont be able to pull/push project code unless you + %strong + = link_to new_key_path, class: "vlink" do + add SSH key + to your profile diff --git a/app/views/snippets/_form.html.haml b/app/views/snippets/_form.html.haml index c9128f642fc..b8d8c09849d 100644 --- a/app/views/snippets/_form.html.haml +++ b/app/views/snippets/_form.html.haml @@ -10,22 +10,22 @@ .clearfix = f.label :title - .input= f.text_field :title, :placeholder => "Example Snippet" + .input= f.text_field :title, placeholder: "Example Snippet" .clearfix = f.label :file_name - .input= f.text_field :file_name, :placeholder => "example.rb" + .input= f.text_field :file_name, placeholder: "example.rb" .clearfix = f.label "Lifetime" - .input= f.select :expires_at, lifetime_select_options, {}, :style => "width:200px;" + .input= f.select :expires_at, lifetime_select_options, {}, style: "width:200px;" .clearfix = f.label :content, "Code" - .input= f.text_area :content, :class => "span8" + .input= f.text_area :content, class: "span8" .actions - = f.submit 'Save', :class => "primary btn" - = link_to "Cancel", project_snippets_path(@project), :class => " btn" + = f.submit 'Save', class: "primary btn" + = link_to "Cancel", project_snippets_path(@project), class: " btn" - unless @snippet.new_record? - .right= link_to 'Destroy', [@project, @snippet], :confirm => 'Are you sure?', :method => :delete, :class => "btn right danger delete-snippet", :id => "destroy_snippet_#{@snippet.id}" + .right= link_to 'Destroy', [@project, @snippet], confirm: 'Are you sure?', method: :delete, class: "btn right danger delete-snippet", id: "destroy_snippet_#{@snippet.id}" diff --git a/app/views/snippets/_snippet.html.haml b/app/views/snippets/_snippet.html.haml index 0385d753207..a2d3a65e6cb 100644 --- a/app/views/snippets/_snippet.html.haml +++ b/app/views/snippets/_snippet.html.haml @@ -1,7 +1,7 @@ %tr %td - %a{:href => project_snippet_path(snippet.project, snippet)} - %strong= truncate(snippet.title, :length => 60) + %a{href: project_snippet_path(snippet.project, snippet)} + %strong= truncate(snippet.title, length: 60) %td = snippet.file_name %td diff --git a/app/views/snippets/index.html.haml b/app/views/snippets/index.html.haml index a6b07716ccb..7229b587bc8 100644 --- a/app/views/snippets/index.html.haml +++ b/app/views/snippets/index.html.haml @@ -2,9 +2,9 @@ - if can? current_user, :write_snippet, @project .alert-message.block-message - = link_to new_project_snippet_path(@project), :class => "btn small add_new right", :title => "New Snippet" do + = link_to new_project_snippet_path(@project), class: "btn small add_new right", title: "New Snippet" do Add new snippet - Share code pastes with others if it cant be in a git repository + Share code pastes with others if it can't be in a git repository %br To add new snippet - click on button. @@ -17,5 +17,5 @@ = render @snippets.fresh - if @snippets.fresh.empty? %tr - %td{:colspan => 3} + %td{colspan: 3} %h3.nothing_here_message Nothing here. diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml index b266e4d2156..0800b81d330 100644 --- a/app/views/snippets/show.html.haml +++ b/app/views/snippets/show.html.haml @@ -4,7 +4,7 @@ = @snippet.title %small= @snippet.file_name - if can?(current_user, :admin_snippet, @project) || @snippet.author == current_user - = link_to "Edit", edit_project_snippet_path(@project, @snippet), :class => "btn small right" + = link_to "Edit", edit_project_snippet_path(@project, @snippet), class: "btn small right" %br .file_holder @@ -12,9 +12,9 @@ %i.icon-file %strong= @snippet.file_name %span.options - = link_to "raw", raw_project_snippet_path(@project, @snippet), :class => "btn very_small", :target => "_blank" + = link_to "raw", raw_project_snippet_path(@project, @snippet), class: "btn very_small", target: "_blank" .file_content.code - %div{:class => current_user.dark_scheme ? "black" : ""} + %div{class: current_user.dark_scheme ? "black" : ""} = raw @snippet.colorize(options: { linenos: 'True'}) -= render "notes/notes", :tid => @snippet.id, :tt => "snippet" += render "notes/notes", tid: @snippet.id, tt: "snippet" diff --git a/app/views/team_members/_form.html.haml b/app/views/team_members/_form.html.haml index 1d882e295d9..208794b9ee2 100644 --- a/app/views/team_members/_form.html.haml +++ b/app/views/team_members/_form.html.haml @@ -1,6 +1,6 @@ %h3= "New Team member" %hr -= form_for @team_member, :as => :team_member, :url => project_team_members_path(@project, @team_member) do |f| += form_for @team_member, as: :team_member, url: project_team_members_path(@project, @team_member) do |f| -if @team_member.errors.any? .alert-message.block-message.error %ul @@ -9,17 +9,17 @@ .clearfix = f.label :user_id, "Name" - .input= f.select(:user_id, User.not_in_project(@project).all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" }, { :style => "width:300px" }) + .input= f.select(:user_id, User.not_in_project(@project).all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, { style: "width:300px" }) .clearfix = f.label :project_access, "Project Access" - .input= f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, :class => "project-access-select" + .input= f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, class: "project-access-select" .actions - = f.submit 'Save', :class => "btn primary" - = link_to "Cancel", team_project_path(@project), :class => "btn" + = f.submit 'Save', class: "btn primary" + = link_to "Cancel", team_project_path(@project), class: "btn" :css form select { diff --git a/app/views/team_members/_show.html.haml b/app/views/team_members/_show.html.haml index 9f023c416ae..2dc4fb652dd 100644 --- a/app/views/team_members/_show.html.haml +++ b/app/views/team_members/_show.html.haml @@ -1,6 +1,6 @@ - user = member.user - allow_admin = can? current_user, :admin_project, @project -%tr{:id => dom_id(member), :class => "team_member_row user_#{user.id}"} +%tr{id: dom_id(member), class: "team_member_row user_#{user.id}"} %td .right - if @project.owner == user @@ -8,13 +8,13 @@ - if user.blocked %span.label Blocked - = link_to project_team_member_path(@project, member), :title => user.name, :class => "dark" do - = image_tag gravatar_icon(user.email, 40), :class => "avatar" - = link_to project_team_member_path(@project, member), :title => user.name, :class => "dark" do - %strong= truncate(user.name, :lenght => 40) + = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do + = image_tag gravatar_icon(user.email, 40), class: "avatar s32" + = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do + %strong= truncate(user.name, lenght: 40) %br %div.cgray= user.email %td - = form_for(member, :as => :team_member, :url => project_team_member_path(@project, member)) do |f| - = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, :class => "medium project-access-select", :disabled => !allow_admin + = form_for(member, as: :team_member, url: project_team_member_path(@project, member)) do |f| + = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select", disabled: !allow_admin diff --git a/app/views/team_members/show.html.haml b/app/views/team_members/show.html.haml index f8a203d43c1..6cb357cddfc 100644 --- a/app/views/team_members/show.html.haml +++ b/app/views/team_members/show.html.haml @@ -2,16 +2,19 @@ - user = @team_member.user .team_member_show + - if can? current_user, :admin_project, @project + = link_to 'Remove from team', project_team_member_path(project_id: @project, id: @team_member.id), confirm: 'Are you sure?', method: :delete, class: "right btn btn-danger" .profile_avatar_holder - = image_tag gravatar_icon(user.email, 60), :class => "borders" + = image_tag gravatar_icon(user.email, 60), class: "borders" %h3 = user.name %small = user.email + %hr .back_link %br - = link_to team_project_path(@project), :class => "" do + = link_to team_project_path(@project), class: "" do ← To team list %br .row @@ -43,17 +46,12 @@ %tr %td Project Access: - %small (#{link_to "read more", help_permissions_path, :class => "vlink"}) + %small (#{link_to "read more", help_permissions_path, class: "vlink"}) %td - = form_for(@team_member, :as => :team_member, :url => project_team_member_path(@project, @team_member)) do |f| - = f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, :class => "project-access-select", :disabled => !allow_admin + = form_for(@team_member, as: :team_member, url: project_team_member_path(@project, @team_member)) do |f| + = f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, class: "project-access-select", disabled: !allow_admin %hr - = render user.recent_events.limit(3) - - if can? current_user, :admin_project, @project - .form-horizontal - .form-actions - = link_to 'Remove from team', project_team_member_path(:project_id => @project, :id => @team_member.id), :confirm => 'Are you sure?', :method => :delete, :class => "btn btn-danger" - + = render @events :javascript $(function(){ $('.repo-access-select, .project-access-select').live("change", function() { diff --git a/app/views/wikis/_form.html.haml b/app/views/wikis/_form.html.haml index dbb8648d664..6b6411be55b 100644 --- a/app/views/wikis/_form.html.haml +++ b/app/views/wikis/_form.html.haml @@ -6,19 +6,21 @@ - @wiki.errors.full_messages.each do |msg| %li= msg - .alert-message.block-message.warning - %p - Wiki content is parsed with #{link_to "Markdown", "http://en.wikipedia.org/wiki/Markdown"}. - %br - To add link to new page you can just type - %code [Link Title](page-slug) - .clearfix - = f.label :title - .input= f.text_field :title, :class => :xxlarge - = f.hidden_field :slug - .clearfix - = f.label :content - .input= f.text_area :content, :class => :xxlarge + .main_box + .top_box_content + = f.label :title + .input= f.text_field :title, class: 'span8' + = f.hidden_field :slug + .middle_box_content + .input + %span.cgray + Wiki content is parsed with #{link_to "Markdown", "http://en.wikipedia.org/wiki/Markdown"}. + To add link to new page you can just type + %code [Link Title](page-slug) + + .bottom_box_content + = f.label :content + .input= f.text_area :content, class: 'span8' .actions - = f.submit 'Save', :class => "primary btn" - = link_to "Cancel", project_wiki_path(@project, :index), :class => "btn" + = f.submit 'Save', class: "primary btn" + = link_to "Cancel", project_wiki_path(@project, :index), class: "btn" diff --git a/app/views/wikis/edit.html.haml b/app/views/wikis/edit.html.haml index 26cbd52a9a8..27d2a8f915f 100644 --- a/app/views/wikis/edit.html.haml +++ b/app/views/wikis/edit.html.haml @@ -1,3 +1,3 @@ -%h3 Editing page +%h3.page_title Editing page %hr = render 'form' diff --git a/app/views/wikis/empty.html.haml b/app/views/wikis/empty.html.haml new file mode 100644 index 00000000000..32b1c9258c5 --- /dev/null +++ b/app/views/wikis/empty.html.haml @@ -0,0 +1,4 @@ +%h3.page_title Empty page +%hr +.alert-message.block-message.warning + %span You are not allowed to create wiki pages diff --git a/app/views/wikis/history.html.haml b/app/views/wikis/history.html.haml index 6a9b56ae771..e31c5dc2426 100644 --- a/app/views/wikis/history.html.haml +++ b/app/views/wikis/history.html.haml @@ -1,5 +1,8 @@ -%h3 Versions -%table +%h3.page_title + %span.cgray History for + = @wikis.last.title +%br +%table.admin-table %thead %tr %th # @@ -10,7 +13,7 @@ %tr %td= i + 1 %td - = link_to wiki_page.created_at.to_s(:short), project_wiki_path(@project, wiki_page, :old_page_id => wiki_page.id) + = link_to wiki_page.created_at.to_s(:short), project_wiki_path(@project, wiki_page, old_page_id: wiki_page.id) (#{time_ago_in_words(wiki_page.created_at)} ago) %td= wiki_page.user.name diff --git a/app/views/wikis/pages.html.haml b/app/views/wikis/pages.html.haml new file mode 100644 index 00000000000..2bfd0deb149 --- /dev/null +++ b/app/views/wikis/pages.html.haml @@ -0,0 +1,18 @@ +%h3.page_title All Pages +%br +%table.admin-table + %thead + %tr + %th Title + %th slug + %th created by + %tbody + - @wikis.each_with_index do |wiki_page, i| + %tr + %td + = link_to wiki_page.title, project_wiki_path(@project, wiki_page, old_page_id: wiki_page.id) + (#{time_ago_in_words(wiki_page.created_at)} + ago) + %td= wiki_page.slug + %td= wiki_page.user.name + diff --git a/app/views/wikis/show.html.haml b/app/views/wikis/show.html.haml index 9aa287dff07..fc2352271d5 100644 --- a/app/views/wikis/show.html.haml +++ b/app/views/wikis/show.html.haml @@ -1,17 +1,24 @@ -%h3 +%h3.page_title = @wiki.title %span.right + = link_to pages_project_wikis_path(@project), class: "btn small grouped" do + Pages - if can? current_user, :write_wiki, @project - = link_to history_project_wiki_path(@project, @wiki), :class => "btn small grouped" do + = link_to history_project_wiki_path(@project, @wiki), class: "btn small grouped" do History - = link_to edit_project_wiki_path(@project, @wiki), :class => "btn small grouped" do + = link_to edit_project_wiki_path(@project, @wiki), class: "btn small grouped" do + %i.icon-edit Edit -%hr -.wiki_content - = preserve do - = markdown @wiki.content +%br +.file_holder + .file_content.wiki + = preserve do + = markdown @wiki.content %p.time Last edited by #{@wiki.user.name}, #{time_ago_in_words @wiki.created_at} ago - if can? current_user, :admin_wiki, @project - = link_to project_wiki_path(@project, @wiki), :confirm => "Are you sure you want to delete this page?", :method => :delete do + = link_to project_wiki_path(@project, @wiki), confirm: "Are you sure you want to delete this page?", method: :delete do Delete this page + +%hr +.wiki_notes#notes= render "notes/notes", tid: @wiki.id, tt: "wiki" diff --git a/app/workers/system_hook_worker.rb b/app/workers/system_hook_worker.rb new file mode 100644 index 00000000000..ca154136b97 --- /dev/null +++ b/app/workers/system_hook_worker.rb @@ -0,0 +1,7 @@ +class SystemHookWorker + @queue = :system_hook + + def self.perform(hook_id, data) + SystemHook.find(hook_id).execute data + end +end diff --git a/config/application.rb b/config/application.rb index 3585c4b0a87..ecd88b15d15 100644 --- a/config/application.rb +++ b/config/application.rb @@ -23,7 +23,7 @@ module Gitlab # config.plugins = [ :exception_notification, :ssl_requirement, :all ] # Activate observers that should always be running. - config.active_record.observers = :mailer_observer, :activity_observer, :project_observer, :key_observer, :issue_observer, :user_observer + config.active_record.observers = :mailer_observer, :activity_observer, :project_observer, :key_observer, :issue_observer, :user_observer, :system_hook_observer # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. @@ -44,5 +44,8 @@ module Gitlab # Version of your assets, change this if you want to expire all your assets config.assets.version = '1.0' + + # Add fonts + config.assets.paths << "#{Rails.root}/app/assets/fonts" end end diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 1818f2c0d01..be36ee6da0d 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -1,4 +1,4 @@ -# # # # # # # # # # # # # # # # # # +# # # # # # # # # # # # # # # # # # # Gitlab application config file # # # # # # # # # # # # # # # # # # # @@ -19,14 +19,14 @@ email: # Application specific settings # Like default project limit for user etc -app: - default_projects_limit: 10 +app: + default_projects_limit: 10 # backup_path: "/vol/backups" # default: Rails.root + backups/ # backup_keep_time: 604800 # default: 0 (forever) (in seconds) + # disable_gravatar: true # default: false - Disable user avatars from Gravatar.com - -# -# 2. Advanced settings: +# +# 2. Advanced settings: # ========================== # Git Hosting configuration @@ -39,7 +39,6 @@ git_host: receive_pack: true # port: 22 - # Git settings # Use default values unless you understand it git: diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 5c5987a8857..8165d6c2eea 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -111,5 +111,9 @@ class Settings < Settingslogic def backup_keep_time app['backup_keep_time'] || 0 end + + def disable_gravatar? + app['disable_gravatar'] || false + end end end diff --git a/config/initializers/grack_auth.rb b/config/initializers/grack_auth.rb index 5995b873de9..4f77c327373 100644 --- a/config/initializers/grack_auth.rb +++ b/config/initializers/grack_auth.rb @@ -42,13 +42,13 @@ module Grack def current_ref if @env["HTTP_CONTENT_ENCODING"] =~ /gzip/ - input = Zlib::GzipReader.new(@request.body).string + input = Zlib::GzipReader.new(@request.body).read else - input = @request.body.string + input = @request.body.read end - - oldrev, newrev, ref = input.split(' ') - /refs\/heads\/([\w-]+)/.match(ref).to_a.last + # Need to reset seek point + @request.body.rewind + /refs\/heads\/([\w-]+)/.match(input).to_a.first end end# Auth end# Grack diff --git a/config/initializers/omniauth.rb.sample b/config/initializers/omniauth.rb.sample index 8728472f076..6e844efde23 100644 --- a/config/initializers/omniauth.rb.sample +++ b/config/initializers/omniauth.rb.sample @@ -2,7 +2,7 @@ # The wiki has further details on configuring each provider. Devise.setup do |config| - # config.omniauth :github 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo' + # config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo' # config.omniauth :ldap, # :host => 'YOUR_LDAP_SERVER', @@ -12,4 +12,4 @@ Devise.setup do |config| # :method => :plain, # :bind_dn => 'THE_FULL_DN_OF_THE_USER_YOU_WILL_BIND_WITH', # :password => 'THE_PASSWORD_OF_THE_BIND_USER' -end
\ No newline at end of file +end diff --git a/config/initializers/rails_footnotes.rb b/config/initializers/rails_footnotes.rb deleted file mode 100644 index afe6f3ad383..00000000000 --- a/config/initializers/rails_footnotes.rb +++ /dev/null @@ -1,3 +0,0 @@ -#if defined?(Footnotes) && Rails.env.development? - #Footnotes.run! # first of all -#end diff --git a/config/routes.rb b/config/routes.rb index 73b9f643ad5..f895478fb12 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -28,6 +28,9 @@ Gitlab::Application.routes.draw do get 'help/workflow' => 'help#workflow' get 'help/api' => 'help#api' get 'help/web_hooks' => 'help#web_hooks' + get 'help/system_hooks' => 'help#system_hooks' + get 'help/markdown' => 'help#markdown' + get 'help/ssh' => 'help#ssh' # # Admin Area @@ -47,11 +50,13 @@ Gitlab::Application.routes.draw do end end resources :team_members, :only => [:edit, :update, :destroy] - get 'emails', :to => 'mailer#preview' get 'mailer/preview_note' get 'mailer/preview_user_new' get 'mailer/preview_issue_new' + resources :hooks, :only => [:index, :create, :destroy] do + get :test + end resource :logs resource :resque, :controller => 'resque' root :to => "dashboard#index" @@ -94,6 +99,10 @@ Gitlab::Application.routes.draw do end resources :wikis, :only => [:show, :edit, :destroy, :create] do + collection do + get :pages + end + member do get "history" end @@ -188,13 +197,20 @@ Gitlab::Application.routes.draw do end resources :team_members resources :milestones + resources :labels, :only => [:index] resources :issues do + collection do post :sort + post :bulk_update get :search end end - resources :notes, :only => [:index, :create, :destroy] + resources :notes, :only => [:index, :create, :destroy] do + collection do + post :preview + end + end end root :to => "dashboard#index" end diff --git a/db/migrate/20120712080407_add_type_to_web_hook.rb b/db/migrate/20120712080407_add_type_to_web_hook.rb new file mode 100644 index 00000000000..18ab024c817 --- /dev/null +++ b/db/migrate/20120712080407_add_type_to_web_hook.rb @@ -0,0 +1,5 @@ +class AddTypeToWebHook < ActiveRecord::Migration + def change + add_column :web_hooks, :type, :string, :default => "ProjectHook" + end +end diff --git a/db/migrate/20120729131232_add_extern_auth_provider_to_users.rb b/db/migrate/20120729131232_add_extern_auth_provider_to_users.rb new file mode 100644 index 00000000000..d5e66ba4d3b --- /dev/null +++ b/db/migrate/20120729131232_add_extern_auth_provider_to_users.rb @@ -0,0 +1,8 @@ +class AddExternAuthProviderToUsers < ActiveRecord::Migration + def change + add_column :users, :extern_uid, :string + add_column :users, :provider, :string + + add_index :users, [:extern_uid, :provider], :unique => true + end +end diff --git a/db/schema.rb b/db/schema.rb index f40ee260dc3..46461e44aad 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20120706065612) do +ActiveRecord::Schema.define(:version => 20120729131232) do create_table "events", :force => true do |t| t.string "target_type" @@ -171,9 +171,12 @@ ActiveRecord::Schema.define(:version => 20120706065612) do t.boolean "blocked", :default => false, :null => false t.integer "failed_attempts", :default => 0 t.datetime "locked_at" + t.string "extern_uid" + t.string "provider" end add_index "users", ["email"], :name => "index_users_on_email", :unique => true + add_index "users", ["extern_uid", "provider"], :name => "index_users_on_extern_uid_and_provider", :unique => true add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true create_table "users_projects", :force => true do |t| @@ -187,8 +190,9 @@ ActiveRecord::Schema.define(:version => 20120706065612) do create_table "web_hooks", :force => true do |t| t.string "url" t.integer "project_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "type", :default => "ProjectHook" end create_table "wikis", :force => true do |t| diff --git a/doc/api/README.md b/doc/api/README.md index dcf75afda1f..d32573aaa6b 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -27,3 +27,5 @@ The API uses JSON to serialize data. You don't need to specify `.json` at the en + [Users](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/users.md) + [Projects](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/projects.md) ++ [Snippets](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/snippets.md) ++ [Issues](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/issues.md) diff --git a/doc/api/issues.md b/doc/api/issues.md new file mode 100644 index 00000000000..aaad3305489 --- /dev/null +++ b/doc/api/issues.md @@ -0,0 +1,184 @@ +## List issues + +Get all issues created by authenticed user. + +``` +GET /issues +``` + +```json +[ + { + "id": 43, + "project_id": 8, + "title": "4xx/5xx pages", + "description": "", + "labels": [ ], + "milestone": null, + "assignee": null, + "author": { + "id": 1, + "email": "john@example.com", + "name": "John Smith", + "blocked": false, + "created_at": "2012-05-23T08:00:58Z" + }, + "closed": true, + "updated_at": "2012-07-02T17:53:12Z", + "created_at": "2012-07-02T17:53:12Z" + }, + { + "id": 42, + "project_id": 8, + "title": "Add user settings", + "description": "", + "labels": [ + "feature" + ], + "milestone": { + "id": 1, + "title": "v1.0", + "description": "", + "due_date": "2012-07-20", + "closed": false, + "updated_at": "2012-07-04T13:42:48Z", + "created_at": "2012-07-04T13:42:48Z" + }, + "assignee": { + "id": 2, + "email": "jack@example.com", + "name": "Jack Smith", + "blocked": false, + "created_at": "2012-05-23T08:01:01Z" + }, + "author": { + "id": 1, + "email": "john@example.com", + "name": "John Smith", + "blocked": false, + "created_at": "2012-05-23T08:00:58Z" + }, + "closed": false, + "updated_at": "2012-07-12T13:43:19Z", + "created_at": "2012-06-28T12:58:06Z" + } +] +``` + +## List project issues + +Get a list of project issues. + +``` +GET /projects/:id/issues +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project + +## Single issue + +Get a project issue. + +``` +GET /projects/:id/issues/:issue_id +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `issue_id` (required) - The ID of a project issue + +```json +{ + "id": 42, + "project_id": 8, + "title": "Add user settings", + "description": "", + "labels": [ + "feature" + ], + "milestone": { + "id": 1, + "title": "v1.0", + "description": "", + "due_date": "2012-07-20", + "closed": false, + "updated_at": "2012-07-04T13:42:48Z", + "created_at": "2012-07-04T13:42:48Z" + }, + "assignee": { + "id": 2, + "email": "jack@example.com", + "name": "Jack Smith", + "blocked": false, + "created_at": "2012-05-23T08:01:01Z" + }, + "author": { + "id": 1, + "email": "john@example.com", + "name": "John Smith", + "blocked": false, + "created_at": "2012-05-23T08:00:58Z" + }, + "closed": false, + "updated_at": "2012-07-12T13:43:19Z", + "created_at": "2012-06-28T12:58:06Z" +} +``` + +## New issue + +Create a new project issue. + +``` +POST /projects/:id/issues +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `title` (required) - The title of an issue ++ `description` (optional) - The description of an issue ++ `assignee_id` (optional) - The ID of a user to assign issue ++ `milestone_id` (optional) - The ID of a milestone to assign issue ++ `labels` (optional) - Comma-separated label names for an issue + +Will return created issue with status `201 Created` on success, or `404 Not found` on fail. + +## Edit issue + +Update an existing project issue. + +``` +PUT /projects/:id/issues/:issue_id +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `issue_id` (required) - The ID of a project's issue ++ `title` (optional) - The title of an issue ++ `description` (optional) - The description of an issue ++ `assignee_id` (optional) - The ID of a user to assign issue ++ `milestone_id` (optional) - The ID of a milestone to assign issue ++ `labels` (optional) - Comma-separated label names for an issue ++ `closed` (optional) - The state of an issue (0 = false, 1 = true) + +Will return updated issue with status `200 OK` on success, or `404 Not found` on fail. + +## Delete issue + +Delete existing project issue. + +``` +DELETE /projects/:id/issues/:issue_id +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `issue_id` (required) - The ID of a project's issue + +Status code `200` will be returned on success. diff --git a/doc/api/projects.md b/doc/api/projects.md index c748745e063..d680b5d8597 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -1,6 +1,6 @@ ## List projects -Get a list of authenticated users' projects. +Get a list of authenticated user's projects. ``` GET /projects @@ -63,7 +63,7 @@ GET /projects/:id Parameters: -+ `id` (required) - The code name of a project ++ `id` (required) - The ID or code name of a project ```json { @@ -91,7 +91,7 @@ Parameters: ## Project repository branches -Get a list of project repository branches. +Get a list of project repository branches sorted by name alphabetically. ``` GET /projects/:id/repository/branches @@ -99,7 +99,7 @@ GET /projects/:id/repository/branches Parameters: -+ `id` (required) - The code name of a project ++ `id` (required) - The ID or code name of a project ```json [ @@ -129,9 +129,46 @@ Parameters: ] ``` +Get a single project repository branch. + +``` +GET /projects/:id/repository/branches/:branch +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `branch` (required) - The name of the branch + +```json +{ + "name": "master", + "commit": { + "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", + "parents": [ + { + "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8" + } + ], + "tree": "46e82de44b1061621357f24c05515327f2795a95", + "message": "add projects API", + "author": { + "name": "John Smith", + "email": "john@example.com" + }, + "committer": { + "name": "John Smith", + "email": "john@example.com" + }, + "authored_date": "2012-06-27T05:51:39-07:00", + "committed_date": "2012-06-28T03:44:20-07:00" + } +} +``` + ## Project repository tags -Get a list of project repository tags. +Get a list of project repository tags sorted by name in reverse alphabetical order. ``` GET /projects/:id/repository/tags @@ -139,7 +176,7 @@ GET /projects/:id/repository/tags Parameters: -+ `id` (required) - The code name of a project ++ `id` (required) - The ID or code name of a project ```json [ @@ -167,104 +204,18 @@ Parameters: ] ``` -# Project Snippets - -## List snippets - -Not implemented. - -## Single snippet - -Get a project snippet. - -``` -GET /projects/:id/snippets/:snippet_id -``` - -Parameters: - -+ `id` (required) - The code name of a project -+ `snippet_id` (required) - The ID of a project's snippet - -```json -{ - "id": 1, - "title": "test", - "file_name": "add.rb", - "author": { - "id": 1, - "email": "john@example.com", - "name": "John Smith", - "blocked": false, - "created_at": "2012-05-23T08:00:58Z" - }, - "expires_at": null, - "updated_at": "2012-06-28T10:52:04Z", - "created_at": "2012-06-28T10:52:04Z" -} -``` - -## Snippet content - -Get a raw project snippet. - -``` -GET /projects/:id/snippets/:snippet_id/raw -``` - -Parameters: - -+ `id` (required) - The code name of a project -+ `snippet_id` (required) - The ID of a project's snippet - -## New snippet - -Create a new project snippet. - -``` -POST /projects/:id/snippets -``` - -Parameters: - -+ `id` (required) - The code name of a project -+ `title` (required) - The title of a snippet -+ `file_name` (required) - The name of a snippet file -+ `lifetime` (optional) - The expiration date of a snippet -+ `code` (required) - The content of a snippet - -Will return created snippet with status `201 Created` on success, or `404 Not found` on fail. - -## Edit snippet - -Update an existing project snippet. - -``` -PUT /projects/:id/snippets/:snippet_id -``` - -Parameters: - -+ `id` (required) - The code name of a project -+ `snippet_id` (required) - The ID of a project's snippet -+ `title` (optional) - The title of a snippet -+ `file_name` (optional) - The name of a snippet file -+ `lifetime` (optional) - The expiration date of a snippet -+ `code` (optional) - The content of a snippet - -Will return updated snippet with status `200 OK` on success, or `404 Not found` on fail. - -## Delete snippet +## Raw blob content -Delete existing project snippet. +Get the raw file contents for a file. ``` -DELETE /projects/:id/snippets/:snippet_id +GET /projects/:id/repository/commits/:sha/blob ``` Parameters: -+ `id` (required) - The code name of a project -+ `snippet_id` (required) - The ID of a project's snippet ++ `id` (required) - The ID or code name of a project ++ `sha` (required) - The commit or branch name ++ `filepath` (required) - The path the file -Status code `200` will be returned on success. +Will return the raw file contents. diff --git a/doc/api/snippets.md b/doc/api/snippets.md new file mode 100644 index 00000000000..0cd29ce530b --- /dev/null +++ b/doc/api/snippets.md @@ -0,0 +1,100 @@ +## List snippets + +Not implemented. + +## Single snippet + +Get a project snippet. + +``` +GET /projects/:id/snippets/:snippet_id +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `snippet_id` (required) - The ID of a project's snippet + +```json +{ + "id": 1, + "title": "test", + "file_name": "add.rb", + "author": { + "id": 1, + "email": "john@example.com", + "name": "John Smith", + "blocked": false, + "created_at": "2012-05-23T08:00:58Z" + }, + "expires_at": null, + "updated_at": "2012-06-28T10:52:04Z", + "created_at": "2012-06-28T10:52:04Z" +} +``` + +## Snippet content + +Get a raw project snippet. + +``` +GET /projects/:id/snippets/:snippet_id/raw +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `snippet_id` (required) - The ID of a project's snippet + +## New snippet + +Create a new project snippet. + +``` +POST /projects/:id/snippets +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `title` (required) - The title of a snippet ++ `file_name` (required) - The name of a snippet file ++ `lifetime` (optional) - The expiration date of a snippet ++ `code` (required) - The content of a snippet + +Will return created snippet with status `201 Created` on success, or `404 Not found` on fail. + +## Edit snippet + +Update an existing project snippet. + +``` +PUT /projects/:id/snippets/:snippet_id +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `snippet_id` (required) - The ID of a project's snippet ++ `title` (optional) - The title of a snippet ++ `file_name` (optional) - The name of a snippet file ++ `lifetime` (optional) - The expiration date of a snippet ++ `code` (optional) - The content of a snippet + +Will return updated snippet with status `200 OK` on success, or `404 Not found` on fail. + +## Delete snippet + +Delete existing project snippet. + +``` +DELETE /projects/:id/snippets/:snippet_id +``` + +Parameters: + ++ `id` (required) - The ID or code name of a project ++ `snippet_id` (required) - The ID of a project's snippet + +Status code `200` will be returned on success. + diff --git a/doc/debian_ubuntu.sh b/doc/debian_ubuntu.sh index 11533285849..a0b4710b5eb 100644 --- a/doc/debian_ubuntu.sh +++ b/doc/debian_ubuntu.sh @@ -3,7 +3,7 @@ sudo apt-get update sudo apt-get upgrade -sudo apt-get install -y git git-core wget curl gcc checkinstall libxml2-dev libxslt-dev sqlite3 libsqlite3-dev libcurl4-openssl-dev libreadline-gplv2-dev libc6-dev libssl-dev libmysql++-dev make build-essential zlib1g-dev libicu-dev redis-server openssh-server python-dev python-pip libyaml-dev +sudo apt-get install -y git git-core wget curl gcc checkinstall libxml2-dev libxslt-dev sqlite3 libsqlite3-dev libcurl4-openssl-dev libreadline-gplv2-dev libc6-dev libssl-dev libmysql++-dev make build-essential zlib1g-dev libicu-dev redis-server openssh-server python-dev python-pip libyaml-dev postfix wget http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p194.tar.gz tar xfvz ruby-1.9.3-p194.tar.gz diff --git a/doc/installation.md b/doc/installation.md index 3dfedfe10ad..1d32e1b7582 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -60,7 +60,7 @@ Also read the [Read this before you submit an issue](https://github.com/gitlabhq sudo apt-get update sudo apt-get upgrade - sudo apt-get install -y wget curl gcc checkinstall libxml2-dev libxslt-dev sqlite3 libsqlite3-dev libcurl4-openssl-dev libreadline6-dev libc6-dev libssl-dev libmysql++-dev make build-essential zlib1g-dev libicu-dev redis-server openssh-server git-core python-dev python-pip libyaml-dev sendmail + sudo apt-get install -y wget curl gcc checkinstall libxml2-dev libxslt-dev sqlite3 libsqlite3-dev libcurl4-openssl-dev libreadline6-dev libc6-dev libssl-dev libmysql++-dev make build-essential zlib1g-dev libicu-dev redis-server openssh-server git-core python-dev python-pip libyaml-dev postfix # If you want to use MySQL: sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev @@ -133,7 +133,7 @@ Permissions: # 4. Install gitlab and configuration. Check status configuration. - sudo gem install charlock_holmes + sudo gem install charlock_holmes --version '0.6.8' sudo pip install pygments sudo gem install bundler cd /home/gitlab @@ -152,8 +152,22 @@ Permissions: # Or # Mysql + # Install MySQL as directed in Step #1 + + # Login to MySQL + $ mysql -u root -p + + # Create the gitlabhq production database + mysql> CREATE DATABASE IF NOT EXISTS `gitlabhq_production` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`; + + # Create the MySQL User change $password to a real password + mysql> CREATE USER 'gitlab'@'localhost' IDENTIFIED BY '$password'; + + # Grant proper permissions to the MySQL User + mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON `gitlabhq_production`.* TO 'gitlab'@'localhost'; + + # Exit MySQL Server and copy the example config, make sure to update username/password in config/database.yml sudo -u gitlab cp config/database.yml.example config/database.yml - # Change username/password of config/database.yml to real one #### Install gems @@ -162,6 +176,11 @@ Permissions: #### Setup DB sudo -u gitlab bundle exec rake gitlab:app:setup RAILS_ENV=production + +#### Setup gitlab hooks + + sudo cp ./lib/hooks/post-receive /home/git/share/gitolite/hooks/common/post-receive + sudo chown git:git /home/git/share/gitolite/hooks/common/post-receive Checking status: @@ -181,6 +200,7 @@ Checking status: Resolving deltas: 100% (174/174), done. Can clone gitolite-admin?............YES UMASK for .gitolite.rc is 0007? ............YES + /home/git/share/gitolite/hooks/common/post-receive exists? ............YES If you got all YES - congrats! You can go to next step. @@ -194,14 +214,20 @@ Application can be started with next command: # As daemon sudo -u gitlab bundle exec rails s -e production -d +You can login via web using admin generated with setup: + + admin@local.host + 5iveL!fe + # 6. Run resque process (for processing queue). # Manually sudo -u gitlab bundle exec rake environment resque:work QUEUE=* RAILS_ENV=production BACKGROUND=yes # Gitlab start script - ./resque.sh - + sudo -u gitlab ./resque.sh + # if you run this as root /home/gitlab/gitlab/tmp/pids/resque_worker.pid will be owned by root + # causing the resque worker not to start via init script on next boot/service restart **Ok - we have a working application now. ** **But keep going - there are some thing that should be done ** @@ -301,13 +327,11 @@ Create init script in /etc/init.d/gitlab: restart) echo -n "Restarting $DESC: " kill -USR2 `cat $PID` - kill -USR2 `cat $RESQUE_PID` echo "$NAME." ;; reload) echo -n "Reloading $DESC configuration: " kill -HUP `cat $PID` - kill -HUP `cat $RESQUE_PID` echo "$NAME." ;; *) diff --git a/features/dashboard/dashboard.feature b/features/dashboard/dashboard.feature index 2d66af53b7b..a8c2205c143 100644 --- a/features/dashboard/dashboard.feature +++ b/features/dashboard/dashboard.feature @@ -10,7 +10,7 @@ Feature: Dashboard Then I should see "Shop" project link Then I should see project "Shop" activity feed - Scenario: I should see last pish widget + Scenario: I should see last push widget Then I should see last push widget And I click "Create Merge Request" link Then I see prefilled new Merge Request page diff --git a/features/dashboard/issues.feature b/features/dashboard/issues.feature new file mode 100644 index 00000000000..c3361bb313f --- /dev/null +++ b/features/dashboard/issues.feature @@ -0,0 +1,8 @@ +Feature: Dashboard Issues + Background: + Given I signin as a user + And I have assigned issues + And I visit dashboard issues page + + Scenario: I should see issues list + Then I should see issues assigned to me diff --git a/features/dashboard/merge_requests.feature b/features/dashboard/merge_requests.feature new file mode 100644 index 00000000000..90b8749c5a7 --- /dev/null +++ b/features/dashboard/merge_requests.feature @@ -0,0 +1,8 @@ +Feature: Dashboard MR + Background: + Given I signin as a user + And I have authored merge requests + And I visit dashboard merge requests page + + Scenario: I should see projects list + Then I should see my merge requests diff --git a/features/profile/profile.feature b/features/profile/profile.feature index e3d71abc746..afda4b55081 100644 --- a/features/profile/profile.feature +++ b/features/profile/profile.feature @@ -6,6 +6,11 @@ Feature: Profile Given I visit profile page Then I should see my profile info + Scenario: I edit profile + Given I visit profile page + Then I change my contact info + And I should see new contact info + Scenario: I change my password Given I visit profile password page Then I change my password @@ -15,4 +20,3 @@ Feature: Profile Given I visit profile token page Then I reset my token And I should see new token - diff --git a/features/projects/commits/branches.feature b/features/projects/commits/branches.feature index 2b136e1b582..74575c51c5a 100644 --- a/features/projects/commits/branches.feature +++ b/features/projects/commits/branches.feature @@ -2,9 +2,19 @@ Feature: Browse branches Background: Given I signin as a user And I own project "Shop" + And project "Shop" has protected branches Given I visit project branches page - Scenario: I can see all git branches + Scenario: I can see project recent git branches + Then I should see "Shop" recent branches list + + Scenario: I can see project all git branches + Given I click link "All" + Then I should see "Shop" all branches list + + Scenario: I can see project protected git branches + Given I click link "Protected" + Then I should see "Shop" protected branches list Scenario: I can download project by branch diff --git a/features/projects/commits/commit_comments.feature b/features/projects/commits/commit_comments.feature index bdf47b88fc3..9bd56d29f1e 100644 --- a/features/projects/commits/commit_comments.feature +++ b/features/projects/commits/commit_comments.feature @@ -4,4 +4,7 @@ Feature: Comment commit And I own project "Shop" Given I visit project commit page - Scenario: I leave a comment for commit + @javascript + Scenario: I comment commit + Given I leave a comment like "XML attached" + Then I should see comment "XML attached" diff --git a/features/projects/commits/tags.feature b/features/projects/commits/tags.feature index 81221748500..f7899fc3ce0 100644 --- a/features/projects/commits/tags.feature +++ b/features/projects/commits/tags.feature @@ -5,7 +5,6 @@ Feature: Browse tags Given I visit project tags page Scenario: I can see all git tags + Then I should see "Shop" all tags list Scenario: I can download project by tag - - diff --git a/features/projects/issues/issues.feature b/features/projects/issues/issues.feature index 0ca0792dd8a..180710cf6bc 100644 --- a/features/projects/issues/issues.feature +++ b/features/projects/issues/issues.feature @@ -7,6 +7,32 @@ Feature: Issues And I visit project "Shop" issues page Scenario: I should see open issues - Given I should see "Release 0.4" open issue - And I should not see "Release 0.3" closed issue + Given I should see "Release 0.4" in issues + And I should not see "Release 0.3" in issues + Scenario: I should see closed issues + Given I click link "Closed" + Then I should see "Release 0.3" in issues + And I should not see "Release 0.4" in issues + + Scenario: I should see all issues + Given I click link "All" + Then I should see "Release 0.3" in issues + And I should see "Release 0.4" in issues + + Scenario: I visit issue page + Given I click link "Release 0.4" + Then I should see issue "Release 0.4" + + @javascript + Scenario: I submit new unassigned issue + Given I click link "New Issue" + And I submit new issue "500 error on profile" + Given I click link "500 error on profile" + Then I should see issue "500 error on profile" + + @javascript + Scenario: I comment issue + Given I visit issue page "Release 0.4" + And I leave a comment like "XML attached" + Then I should see comment "XML attached" diff --git a/features/projects/issues/labels.feature b/features/projects/issues/labels.feature new file mode 100644 index 00000000000..5a20bfd6d14 --- /dev/null +++ b/features/projects/issues/labels.feature @@ -0,0 +1,13 @@ +Feature: Labels + Background: + Given I signin as a user + And I own project "Shop" + And project "Shop" have issues tags: + | name | + | bug | + | feature | + Given I visit project "Shop" labels page + + Scenario: I should see active milestones + Then I should see label "bug" + And I should see label "feature" diff --git a/features/projects/issues/milestones.feature b/features/projects/issues/milestones.feature index e69de29bb2d..d78096a4f16 100644 --- a/features/projects/issues/milestones.feature +++ b/features/projects/issues/milestones.feature @@ -0,0 +1,18 @@ +Feature: Milestones + Background: + Given I signin as a user + And I own project "Shop" + And project "Shop" has milestone "v2.2" + Given I visit project "Shop" milestones page + + Scenario: I should see active milestones + Then I should see milestone "v2.2" + + Scenario: I should see milestone + Given I click link "v2.2" + Then I should see milestone "v2.2" + + Scenario: I create new milestone + Given I click link "New Milestone" + And I submit new milestone "v2.3" + Then I should see milestone "v2.3" diff --git a/features/projects/merge_requests.feature b/features/projects/merge_requests.feature index e69de29bb2d..54b6ccde7f9 100644 --- a/features/projects/merge_requests.feature +++ b/features/projects/merge_requests.feature @@ -0,0 +1,42 @@ +Feature: Merge Requests + Background: + Given I signin as a user + And I own project "Shop" + And project "Shop" have "Bug NS-04" open merge request + And project "Shop" have "Feature NS-03" closed merge request + And I visit project "Shop" merge requests page + + Scenario: I should see open merge requests + Then I should see "Bug NS-04" in merge requests + And I should not see "Feature NS-03" in merge requests + + Scenario: I should see closed merge requests + Given I click link "Closed" + Then I should see "Feature NS-03" in merge requests + And I should not see "Bug NS-04" in merge requests + + Scenario: I should see all merge requests + Given I click link "All" + Then I should see "Feature NS-03" in merge requests + And I should see "Bug NS-04" in merge requests + + Scenario: I visit merge request page + Given I click link "Bug NS-04" + Then I should see merge request "Bug NS-04" + + Scenario: I close merge request page + Given I click link "Bug NS-04" + And I click link "Close" + Then I should see closed merge request "Bug NS-04" + + Scenario: I submit new unassigned merge request + Given I click link "New Merge Request" + And I submit new merge request "Wiki Feature" + Then I should see merge request "Wiki Feature" + + @javascript + Scenario: I comment merge request + Given I visit merge request page "Bug NS-04" + And I leave a comment like "XML attached" + Then I should see comment "XML attached" + diff --git a/features/projects/network.feature b/features/projects/network.feature index 9655184cfe1..61c05eb367e 100644 --- a/features/projects/network.feature +++ b/features/projects/network.feature @@ -4,9 +4,7 @@ Feature: Project Network Graph Background: Given I signin as a user And I own project "Shop" - And I visit project "Shop" network page + And I visit project "Shop" network page Scenario: I should see project network Then page should have network graph - - diff --git a/features/projects/project.feature b/features/projects/project.feature new file mode 100644 index 00000000000..895a928ff81 --- /dev/null +++ b/features/projects/project.feature @@ -0,0 +1,11 @@ +Feature: Project + Background: + Given I signin as a user + And I own project "Shop" + And I visit project "Shop" page + + Scenario: I should see project activity + + Scenario: I edit project + + Scenario: I visit attachments diff --git a/features/projects/source/browse_files.feature.commented b/features/projects/source/browse_files.feature index 04aebc19732..04aebc19732 100644 --- a/features/projects/source/browse_files.feature.commented +++ b/features/projects/source/browse_files.feature diff --git a/features/projects/source/git_blame.feature b/features/projects/source/git_blame.feature index e69de29bb2d..6aa6be47deb 100644 --- a/features/projects/source/git_blame.feature +++ b/features/projects/source/git_blame.feature @@ -0,0 +1,10 @@ +Feature: Browse git repo + Background: + Given I signin as a user + And I own project "Shop" + Given I visit project source page + + Scenario: I blame file + Given I click on file from repo + And I click blame button + Then I should see git file blame diff --git a/features/projects/wiki.feature b/features/projects/wiki.feature index ed69e87c91a..4441ada2847 100644 --- a/features/projects/wiki.feature +++ b/features/projects/wiki.feature @@ -7,3 +7,9 @@ Feature: Wiki Scenario: Add new page Given I create Wiki page Then I should see newly created wiki page + + @javascript + Scenario: I comment wiki page + Given I create Wiki page + And I leave a comment like "XML attached" + Then I should see comment "XML attached" diff --git a/features/step_definitions/dashboard_steps.rb b/features/step_definitions/dashboard_steps.rb index 7133d799995..d910ec90d19 100644 --- a/features/step_definitions/dashboard_steps.rb +++ b/features/step_definitions/dashboard_steps.rb @@ -65,3 +65,63 @@ Given /^I search for "(.*?)"$/ do |arg1| fill_in "dashboard_search", :with => arg1 click_button "Search" end + +Given /^I visit dashboard issues page$/ do + visit dashboard_issues_path +end + +Then /^I should see issues assigned to me$/ do + issues = @user.issues + issues.each do |issue| + page.should have_content(issue.title[0..10]) + page.should have_content(issue.project.name) + end +end + +Given /^I visit dashboard merge requests page$/ do + visit dashboard_merge_requests_path +end + +Then /^I should see my merge requests$/ do + merge_requests = @user.merge_requests + merge_requests.each do |mr| + page.should have_content(mr.title[0..10]) + page.should have_content(mr.project.name) + end +end + +Given /^I have assigned issues$/ do + project = Factory :project + project.add_access(@user, :read, :write) + + issue1 = Factory :issue, + :author => @user, + :assignee => @user, + :project => project + + issue2 = Factory :issue, + :author => @user, + :assignee => @user, + :project => project +end + +Given /^I have authored merge requests$/ do + project1 = Factory :project, + :path => "gitlabhq_1", + :code => "gitlabhq_1" + + project2 = Factory :project, + :path => "gitlabhq_2", + :code => "gitlabhq_2" + + project1.add_access(@user, :read, :write) + project2.add_access(@user, :read, :write) + + merge_request1 = Factory :merge_request, + :author => @user, + :project => project1 + + merge_request2 = Factory :merge_request, + :author => @user, + :project => project2 +end diff --git a/features/step_definitions/profile_keys_steps.rb b/features/step_definitions/profile/profile_keys_steps.rb index 5ab7e0480ad..5ab7e0480ad 100644 --- a/features/step_definitions/profile_keys_steps.rb +++ b/features/step_definitions/profile/profile_keys_steps.rb diff --git a/features/step_definitions/profile_steps.rb b/features/step_definitions/profile/profile_steps.rb index 7510c5365e1..4661139c180 100644 --- a/features/step_definitions/profile_steps.rb +++ b/features/step_definitions/profile/profile_steps.rb @@ -36,3 +36,16 @@ Then /^I should see new token$/ do find("#token").value.should == @user.reload.private_token end +Then /^I change my contact info$/ do + fill_in "user_skype", :with => "testskype" + fill_in "user_linkedin", :with => "testlinkedin" + fill_in "user_twitter", :with => "testtwitter" + click_button "Save" + @user.reload +end + +Then /^I should see new contact info$/ do + @user.skype.should == 'testskype' + @user.linkedin.should == 'testlinkedin' + @user.twitter.should == 'testtwitter' +end diff --git a/features/step_definitions/browse_code_steps.rb b/features/step_definitions/project/browse_code_steps.rb index fc3cf56a83b..7f9001bb989 100644 --- a/features/step_definitions/browse_code_steps.rb +++ b/features/step_definitions/project/browse_code_steps.rb @@ -38,3 +38,13 @@ end Then /^I should see raw file content$/ do page.source.should == ValidCommit::BLOB_FILE end + +Given /^I click blame button$/ do + click_link "blame" +end + +Then /^I should see git file blame$/ do + page.should have_content("rubygems.org") + page.should have_content("Dmitriy Zaporozhets") + page.should have_content("bc3735004cb Moving to rails 3.2") +end diff --git a/features/step_definitions/project_commits_steps.rb b/features/step_definitions/project/project_commits_steps.rb index 9bfccfc06ed..35fcb4d11ab 100644 --- a/features/step_definitions/project_commits_steps.rb +++ b/features/step_definitions/project/project_commits_steps.rb @@ -16,11 +16,11 @@ Given /^I click atom feed link$/ do end Then /^I see commits atom feed$/ do - commit = @project.commit + commit = CommitDecorator.decorate(@project.commit) page.response_headers['Content-Type'].should have_content("application/atom+xml") page.body.should have_selector("title", :text => "Recent commits to #{@project.name}") page.body.should have_selector("author email", :text => commit.author_email) - page.body.should have_selector("entry summary", :text => commit.message) + page.body.should have_selector("entry summary", :text => commit.description) end Given /^I click on commit link$/ do @@ -59,3 +59,30 @@ end Given /^I visit project tags page$/ do visit tags_project_repository_path(@project) end + +Then /^I should see "(.*?)" recent branches list$/ do |arg1| + page.should have_content("Branches") + page.should have_content("master") +end + +Then /^I should see "(.*?)" all branches list$/ do |arg1| + page.should have_content("Branches") + page.should have_content("master") +end + +Then /^I should see "(.*?)" all tags list$/ do |arg1| + page.should have_content("Tags") + page.should have_content("v1.2.1") +end + +Then /^I should see "(.*?)" protected branches list$/ do |arg1| + within "table" do + page.should have_content "stable" + page.should_not have_content "master" + end +end + +Given /^project "(.*?)" has protected branches$/ do |arg1| + project = Project.find_by_name(arg1) + project.protected_branches.create(:name => "stable") +end diff --git a/features/step_definitions/project/project_issues_steps.rb b/features/step_definitions/project/project_issues_steps.rb new file mode 100644 index 00000000000..27de03d5489 --- /dev/null +++ b/features/step_definitions/project/project_issues_steps.rb @@ -0,0 +1,57 @@ +Given /^project "(.*?)" have "(.*?)" open issue$/ do |arg1, arg2| + project = Project.find_by_name(arg1) + Factory.create(:issue, :title => arg2, :project => project, :author => project.users.first) +end + +Given /^project "(.*?)" have "(.*?)" closed issue$/ do |arg1, arg2| + project = Project.find_by_name(arg1) + Factory.create(:issue, :title => arg2, :project => project, :author => project.users.first, :closed => true) +end + +Given /^I visit project "(.*?)" issues page$/ do |arg1| + visit project_issues_path(Project.find_by_name(arg1)) +end + +Given /^I should see "(.*?)" in issues$/ do |arg1| + page.should have_content arg1 +end + +Given /^I should not see "(.*?)" in issues$/ do |arg1| + page.should_not have_content arg1 +end + +Then /^I should see issue "(.*?)"$/ do |arg1| + issue = Issue.find_by_title(arg1) + page.should have_content issue.title + page.should have_content issue.author_name + page.should have_content issue.project.name +end + +Given /^I visit issue page "(.*?)"$/ do |arg1| + issue = Issue.find_by_title(arg1) + visit project_issue_path(issue.project, issue) +end + +Given /^I submit new issue "(.*?)"$/ do |arg1| + fill_in "issue_title", with: arg1 + click_button "Submit new issue" +end + +Given /^project "(.*?)" have issues tags:$/ do |arg1, table| + project = Project.find_by_name(arg1) + table.hashes.each do |hash| + Factory :issue, + project: project, + label_list: [hash[:name]] + end +end + +Given /^I visit project "(.*?)" labels page$/ do |arg1| + visit project_labels_path(Project.find_by_name(arg1)) +end + +Then /^I should see label "(.*?)"$/ do |arg1| + within ".labels-table" do + page.should have_content arg1 + end +end diff --git a/features/step_definitions/project/project_merge_requests_steps.rb b/features/step_definitions/project/project_merge_requests_steps.rb new file mode 100644 index 00000000000..2bdb967d3c5 --- /dev/null +++ b/features/step_definitions/project/project_merge_requests_steps.rb @@ -0,0 +1,47 @@ +Given /^project "(.*?)" have "(.*?)" open merge request$/ do |arg1, arg2| + project = Project.find_by_name(arg1) + Factory.create(:merge_request, :title => arg2, :project => project, :author => project.users.first) +end + +Given /^project "(.*?)" have "(.*?)" closed merge request$/ do |arg1, arg2| + project = Project.find_by_name(arg1) + Factory.create(:merge_request, :title => arg2, :project => project, :author => project.users.first, :closed => true) +end + +Given /^I visit project "(.*?)" merge requests page$/ do |arg1| + visit project_merge_requests_path(Project.find_by_name(arg1)) +end + +Then /^I should see "(.*?)" in merge requests$/ do |arg1| + page.should have_content arg1 +end + +Then /^I should not see "(.*?)" in merge requests$/ do |arg1| + page.should_not have_content arg1 +end + +Then /^I should see merge request "(.*?)"$/ do |arg1| + merge_request = MergeRequest.find_by_title(arg1) + page.should have_content(merge_request.title[0..10]) + page.should have_content(merge_request.target_branch) + page.should have_content(merge_request.source_branch) +end + +Given /^I submit new merge request "(.*?)"$/ do |arg1| + fill_in "merge_request_title", :with => arg1 + select "master", :from => "merge_request_source_branch" + select "stable", :from => "merge_request_target_branch" + click_button "Save" +end + +Given /^I visit merge request page "(.*?)"$/ do |arg1| + mr = MergeRequest.find_by_title(arg1) + visit project_merge_request_path(mr.project, mr) +end + +Then /^I should see closed merge request "(.*?)"$/ do |arg1| + mr = MergeRequest.find_by_title(arg1) + mr.closed.should be_true + page.should have_content "Closed by" +end + diff --git a/features/step_definitions/project/project_milestones_steps.rb b/features/step_definitions/project/project_milestones_steps.rb new file mode 100644 index 00000000000..6749773e2b5 --- /dev/null +++ b/features/step_definitions/project/project_milestones_steps.rb @@ -0,0 +1,38 @@ +Given /^project "(.*?)" has milestone "(.*?)"$/ do |arg1, arg2| + project = Project.find_by_name(arg1) + + milestone = Factory :milestone, + :title => arg2, + :project => project + + 3.times do |i| + issue = Factory :issue, + :project => project, + :milestone => milestone + end +end + +Given /^I visit project "(.*?)" milestones page$/ do |arg1| + @project = Project.find_by_name(arg1) + visit project_milestones_path(@project) +end + +Then /^I should see active milestones$/ do + milestone = @project.milestones.first + page.should have_content(milestone.title[0..10]) + page.should have_content(milestone.expires_at) + page.should have_content("Browse Issues") +end + +Then /^I should see milestone "(.*?)"$/ do |arg1| + milestone = @project.milestones.find_by_title(arg1) + page.should have_content(milestone.title[0..10]) + page.should have_content(milestone.expires_at) + page.should have_content("Browse Issues") +end + +Given /^I submit new milestone "(.*?)"$/ do |arg1| + fill_in "milestone_title", :with => arg1 + click_button "Create milestone" +end + diff --git a/features/step_definitions/project_team_steps.rb b/features/step_definitions/project/project_team_steps.rb index f0bab29a6f8..f0bab29a6f8 100644 --- a/features/step_definitions/project_team_steps.rb +++ b/features/step_definitions/project/project_team_steps.rb diff --git a/features/step_definitions/project_wiki_steps.rb b/features/step_definitions/project/project_wiki_steps.rb index 10de38d9ae3..10de38d9ae3 100644 --- a/features/step_definitions/project_wiki_steps.rb +++ b/features/step_definitions/project/project_wiki_steps.rb diff --git a/features/step_definitions/projects_steps.rb b/features/step_definitions/project/projects_steps.rb index bca1213908d..d981e1f3802 100644 --- a/features/step_definitions/projects_steps.rb +++ b/features/step_definitions/project/projects_steps.rb @@ -1,4 +1,4 @@ -include LoginMacros +include LoginHelpers Given /^I signin as a user$/ do login_as :user @@ -50,8 +50,18 @@ Given /^I write new comment "(.*?)"$/ do |arg1| click_button "Add Comment" end +Given /^I visit project "(.*?)" page$/ do |arg1| + project = Project.find_by_name(arg1) + visit project_path(project) +end + Given /^I visit project "(.*?)" network page$/ do |arg1| project = Project.find_by_name(arg1) + + # Stub out find_all to speed this up (10 commits vs. 650) + commits = Grit::Commit.find_all(project.repo, nil, {max_count: 10}) + Grit::Commit.stub(:find_all).and_return(commits) + visit graph_project_path(project) end @@ -62,7 +72,16 @@ end Given /^page should have network graph$/ do page.should have_content "Project Network Graph" within ".graph" do - page.should have_content "stable" - page.should have_content "notes_refacto..." + page.should have_content "master" + page.should have_content "scss_refactor..." end end + +Given /^I leave a comment like "(.*?)"$/ do |arg1| + fill_in "note_note", :with => arg1 + click_button "Add Comment" +end + +Then /^I should see comment "(.*?)"$/ do |arg1| + page.should have_content(arg1) +end diff --git a/features/step_definitions/project_issues_steps.rb b/features/step_definitions/project_issues_steps.rb deleted file mode 100644 index e83c0e7f399..00000000000 --- a/features/step_definitions/project_issues_steps.rb +++ /dev/null @@ -1,22 +0,0 @@ -Given /^project "(.*?)" have "(.*?)" open issue$/ do |arg1, arg2| - project = Project.find_by_name(arg1) - Factory.create(:issue, :title => arg2, :project => project, :author => project.users.first) -end - -Given /^project "(.*?)" have "(.*?)" closed issue$/ do |arg1, arg2| - project = Project.find_by_name(arg1) - Factory.create(:issue, :title => arg2, :project => project, :author => project.users.first, :closed => true) -end - -Given /^I visit project "(.*?)" issues page$/ do |arg1| - visit project_issues_path(Project.find_by_name(arg1)) -end - -Given /^I should see "(.*?)" open issue$/ do |arg1| - page.should have_content arg1 -end - -Given /^I should not see "(.*?)" closed issue$/ do |arg1| - page.should_not have_content arg1 -end - diff --git a/features/support/env.rb b/features/support/env.rb index ce68081b739..80a465b472c 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -1,28 +1,23 @@ -# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. -# It is recommended to regenerate this file in the future when you upgrade to a -# newer version of cucumber-rails. Consider adding your own code to a new file -# instead of editing this one. Cucumber will automatically load all features/**/*.rb -# files. +unless ENV['CI'] + require 'simplecov' + SimpleCov.start 'rails' +end -require "selenium-webdriver" require 'cucumber/rails' require 'webmock/cucumber' WebMock.allow_net_connect! -require Rails.root.join 'spec/monkeypatch' require Rails.root.join 'spec/factories' -require Rails.root.join 'spec/support/login' +require Rails.root.join 'spec/support/monkeypatch' +require Rails.root.join 'spec/support/login_helpers' require Rails.root.join 'spec/support/valid_commit' -# Capybara defaults to XPath selectors rather than Webrat's default of CSS3. In -# order to ease the transition to Capybara we set the default here. If you'd -# prefer to use XPath just remove this line and adjust any selectors in your -# steps to use the XPath syntax. Capybara.default_selector = :css +Capybara.javascript_driver = :webkit # By default, any exception happening in your Rails application will bubble up -# to Cucumber so that your scenario will fail. This is a different from how -# your application behaves in the production environment, where an error page will +# to Cucumber so that your scenario will fail. This is a different from how +# your application behaves in the production environment, where an error page will # be rendered instead. # # Sometimes we want to override this default behaviour and allow Rails to rescue @@ -45,23 +40,11 @@ rescue NameError raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it." end -# You may also want to configure DatabaseCleaner to use different strategies for certain features and scenarios. -# See the DatabaseCleaner documentation for details. Example: -# -# Before('@no-txn,@selenium,@culerity,@celerity,@javascript') do -# # { :except => [:widgets] } may not do what you expect here -# # as tCucumber::Rails::Database.javascript_strategy overrides -# # this setting. -# DatabaseCleaner.strategy = :truncation -# end -# -# Before('~@no-txn', '~@selenium', '~@culerity', '~@celerity', '~@javascript') do -# DatabaseCleaner.strategy = :transaction -# end -# - -# Possible values are :truncation and :transaction -# The :transaction strategy is faster, but might give you threading problems. -# See https://github.com/cucumber/cucumber-rails/blob/master/features/choose_javascript_database_strategy.feature Cucumber::Rails::Database.javascript_strategy = :truncation +require 'headless' + +headless = Headless.new +headless.start + +require 'cucumber/rspec/doubles' diff --git a/lib/api.rb b/lib/api.rb index e24e0a78f71..3ff3b3836f4 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -3,7 +3,7 @@ Dir["#{Rails.root}/lib/api/*.rb"].each {|file| require file} module Gitlab class API < Grape::API VERSION = 'v2' - version VERSION, :using => :path + version VERSION, using: :path rescue_from ActiveRecord::RecordNotFound do rack_response({'message' => '404 Not found'}.to_json, 404) @@ -15,5 +15,6 @@ module Gitlab mount Users mount Projects + mount Issues end end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 35ad4d430ad..96ccd87a407 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -11,23 +11,33 @@ module Gitlab class Project < Grape::Entity expose :id, :code, :name, :description, :path, :default_branch - expose :owner, :using => Entities::UserBasic - expose :private_flag, :as => :private + expose :owner, using: Entities::UserBasic + expose :private_flag, as: :private expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at end - class ProjectRepositoryBranches < Grape::Entity - expose :name, :commit - end - - class ProjectRepositoryTags < Grape::Entity + class RepoObject < Grape::Entity expose :name, :commit end class ProjectSnippet < Grape::Entity expose :id, :title, :file_name - expose :author, :using => Entities::UserBasic + expose :author, using: Entities::UserBasic expose :expires_at, :updated_at, :created_at end + + class Milestone < Grape::Entity + expose :id, :title, :description, :due_date, :closed, :updated_at, :created_at + end + + class Issue < Grape::Entity + expose :id + expose (:project_id) {|issue| issue.project.id} + expose :title, :description + expose :label_list, as: :labels + expose :milestone, using: Entities::Milestone + expose :assignee, :author, using: Entities::UserBasic + expose :closed, :updated_at, :created_at + end end end diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 424a17b283c..c1ea05667ae 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -4,6 +4,16 @@ module Gitlab @current_user ||= User.find_by_authentication_token(params[:private_token]) end + def user_project + if @project ||= current_user.projects.find_by_id(params[:id]) || + current_user.projects.find_by_code(params[:id]) + else + error!({'message' => '404 Not found'}, 404) + end + + @project + end + def authenticate! error!({'message' => '401 Unauthorized'}, 401) unless current_user end diff --git a/lib/api/issues.rb b/lib/api/issues.rb new file mode 100644 index 00000000000..2abc20ad34e --- /dev/null +++ b/lib/api/issues.rb @@ -0,0 +1,111 @@ +module Gitlab + # Issues API + class Issues < Grape::API + before { authenticate! } + + resource :issues do + # Get currently authenticated user's issues + # + # Example Request: + # GET /issues + get do + present current_user.issues, with: Entities::Issue + end + end + + resource :projects do + # Get a list of project issues + # + # Parameters: + # id (required) - The ID or code name of a project + # Example Request: + # GET /projects/:id/issues + get ":id/issues" do + present user_project.issues, with: Entities::Issue + end + + # Get a single project issue + # + # Parameters: + # id (required) - The ID or code name of a project + # issue_id (required) - The ID of a project issue + # Example Request: + # GET /projects/:id/issues/:issue_id + get ":id/issues/:issue_id" do + @issue = user_project.issues.find(params[:issue_id]) + present @issue, with: Entities::Issue + end + + # Create a new project issue + # + # Parameters: + # id (required) - The ID or code name of a project + # title (required) - The title of an issue + # description (optional) - The description of an issue + # assignee_id (optional) - The ID of a user to assign issue + # milestone_id (optional) - The ID of a milestone to assign issue + # labels (optional) - The labels of an issue + # Example Request: + # POST /projects/:id/issues + post ":id/issues" do + @issue = user_project.issues.new( + title: params[:title], + description: params[:description], + assignee_id: params[:assignee_id], + milestone_id: params[:milestone_id], + label_list: params[:labels] + ) + @issue.author = current_user + + if @issue.save + present @issue, with: Entities::Issue + else + error!({'message' => '404 Not found'}, 404) + end + end + + # Update an existing issue + # + # Parameters: + # id (required) - The ID or code name of a project + # issue_id (required) - The ID of a project issue + # title (optional) - The title of an issue + # description (optional) - The description of an issue + # assignee_id (optional) - The ID of a user to assign issue + # milestone_id (optional) - The ID of a milestone to assign issue + # labels (optional) - The labels of an issue + # closed (optional) - The state of an issue (0 = false, 1 = true) + # Example Request: + # PUT /projects/:id/issues/:issue_id + put ":id/issues/:issue_id" do + @issue = user_project.issues.find(params[:issue_id]) + parameters = { + title: (params[:title] || @issue.title), + description: (params[:description] || @issue.description), + assignee_id: (params[:assignee_id] || @issue.assignee_id), + milestone_id: (params[:milestone_id] || @issue.milestone_id), + label_list: (params[:labels] || @issue.label_list), + closed: (params[:closed] || @issue.closed) + } + + if @issue.update_attributes(parameters) + present @issue, with: Entities::Issue + else + error!({'message' => '404 Not found'}, 404) + end + end + + # Delete a project issue + # + # Parameters: + # id (required) - The ID or code name of a project + # issue_id (required) - The ID of a project issue + # Example Request: + # DELETE /projects/:id/issues/:issue_id + delete ":id/issues/:issue_id" do + @issue = user_project.issues.find(params[:issue_id]) + @issue.destroy + end + end + end +end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 70f8fa2aa62..eb23641c605 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -10,59 +10,67 @@ module Gitlab # GET /projects get do @projects = current_user.projects - present @projects, :with => Entities::Project + present @projects, with: Entities::Project end # Get a single project # # Parameters: - # id (required) - The code of a project + # id (required) - The ID or code name of a project # Example Request: # GET /projects/:id get ":id" do - @project = current_user.projects.find_by_code(params[:id]) - present @project, :with => Entities::Project + present user_project, with: Entities::Project end # Get a project repository branches # # Parameters: - # id (required) - The code of a project + # id (required) - The ID or code name of a project # Example Request: # GET /projects/:id/repository/branches get ":id/repository/branches" do - @project = current_user.projects.find_by_code(params[:id]) - present @project.repo.heads.sort_by(&:name), :with => Entities::ProjectRepositoryBranches + present user_project.repo.heads.sort_by(&:name), with: Entities::RepoObject + end + + # Get a single branch + # + # Parameters: + # id (required) - The ID or code name of a project + # branch (required) - The name of the branch + # Example Request: + # GET /projects/:id/repository/branches/:branch + get ":id/repository/branches/:branch" do + @branch = user_project.repo.heads.find { |item| item.name == params[:branch] } + present @branch, with: Entities::RepoObject end # Get a project repository tags # # Parameters: - # id (required) - The code of a project + # id (required) - The ID or code name of a project # Example Request: # GET /projects/:id/repository/tags get ":id/repository/tags" do - @project = current_user.projects.find_by_code(params[:id]) - present @project.repo.tags.sort_by(&:name).reverse, :with => Entities::ProjectRepositoryTags + present user_project.repo.tags.sort_by(&:name).reverse, with: Entities::RepoObject end # Get a project snippet # # Parameters: - # id (required) - The code of a project + # id (required) - The ID or code name of a project # snippet_id (required) - The ID of a project snippet # Example Request: # GET /projects/:id/snippets/:snippet_id get ":id/snippets/:snippet_id" do - @project = current_user.projects.find_by_code(params[:id]) - @snippet = @project.snippets.find(params[:snippet_id]) - present @snippet, :with => Entities::ProjectSnippet + @snippet = user_project.snippets.find(params[:snippet_id]) + present @snippet, with: Entities::ProjectSnippet end # Create a new project snippet # # Parameters: - # id (required) - The code name of a project + # id (required) - The ID or code name of a project # title (required) - The title of a snippet # file_name (required) - The name of a snippet file # lifetime (optional) - The expiration date of a snippet @@ -70,17 +78,16 @@ module Gitlab # Example Request: # POST /projects/:id/snippets post ":id/snippets" do - @project = current_user.projects.find_by_code(params[:id]) - @snippet = @project.snippets.new( - :title => params[:title], - :file_name => params[:file_name], - :expires_at => params[:lifetime], - :content => params[:code] + @snippet = user_project.snippets.new( + title: params[:title], + file_name: params[:file_name], + expires_at: params[:lifetime], + content: params[:code] ) @snippet.author = current_user if @snippet.save - present @snippet, :with => Entities::ProjectSnippet + present @snippet, with: Entities::ProjectSnippet else error!({'message' => '404 Not found'}, 404) end @@ -89,7 +96,7 @@ module Gitlab # Update an existing project snippet # # Parameters: - # id (required) - The code name of a project + # id (required) - The ID or code name of a project # snippet_id (required) - The ID of a project snippet # title (optional) - The title of a snippet # file_name (optional) - The name of a snippet file @@ -98,17 +105,16 @@ module Gitlab # Example Request: # PUT /projects/:id/snippets/:snippet_id put ":id/snippets/:snippet_id" do - @project = current_user.projects.find_by_code(params[:id]) - @snippet = @project.snippets.find(params[:snippet_id]) + @snippet = user_project.snippets.find(params[:snippet_id]) parameters = { - :title => (params[:title] || @snippet.title), - :file_name => (params[:file_name] || @snippet.file_name), - :expires_at => (params[:lifetime] || @snippet.expires_at), - :content => (params[:code] || @snippet.content) + title: (params[:title] || @snippet.title), + file_name: (params[:file_name] || @snippet.file_name), + expires_at: (params[:lifetime] || @snippet.expires_at), + content: (params[:code] || @snippet.content) } if @snippet.update_attributes(parameters) - present @snippet, :with => Entities::ProjectSnippet + present @snippet, with: Entities::ProjectSnippet else error!({'message' => '404 Not found'}, 404) end @@ -117,28 +123,55 @@ module Gitlab # Delete a project snippet # # Parameters: - # id (required) - The code of a project + # id (required) - The ID or code name of a project # snippet_id (required) - The ID of a project snippet # Example Request: # DELETE /projects/:id/snippets/:snippet_id delete ":id/snippets/:snippet_id" do - @project = current_user.projects.find_by_code(params[:id]) - @snippet = @project.snippets.find(params[:snippet_id]) + @snippet = user_project.snippets.find(params[:snippet_id]) @snippet.destroy end # Get a raw project snippet # # Parameters: - # id (required) - The code of a project + # id (required) - The ID or code name of a project # snippet_id (required) - The ID of a project snippet # Example Request: # GET /projects/:id/snippets/:snippet_id/raw get ":id/snippets/:snippet_id/raw" do - @project = current_user.projects.find_by_code(params[:id]) - @snippet = @project.snippets.find(params[:snippet_id]) + @snippet = user_project.snippets.find(params[:snippet_id]) + content_type 'text/plain' present @snippet.content end + + # Get a raw file contents + # + # Parameters: + # id (required) - The ID or code name of a project + # sha (required) - The commit or branch name + # filepath (required) - The path to the file to display + # Example Request: + # GET /projects/:id/repository/commits/:sha/blob + get ":id/repository/commits/:sha/blob" do + ref = params[:sha] + + commit = user_project.commit ref + error!('404 Commit Not Found', 404) unless commit + + tree = Tree.new commit.tree, user_project, ref, params[:filepath] + error!('404 File Not Found', 404) unless tree.try(:tree) + + if tree.text? + encoding = Gitlab::Encode.detect_encoding(tree.data) + content_type encoding ? "text/plain; charset=#{encoding}" : "text/plain" + else + content_type tree.mime_type + end + + present tree.data + end + end end end diff --git a/lib/api/users.rb b/lib/api/users.rb index ef3762f30fc..81cb2a0e684 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -10,7 +10,7 @@ module Gitlab # GET /users get do @users = User.all - present @users, :with => Entities::User + present @users, with: Entities::User end # Get a single user @@ -21,7 +21,7 @@ module Gitlab # GET /users/:id get ":id" do @user = User.find(params[:id]) - present @user, :with => Entities::User + present @user, with: Entities::User end end @@ -30,7 +30,7 @@ module Gitlab # Example Request: # GET /user get "/user" do - present @current_user, :with => Entities::User + present @current_user, with: Entities::User end end end diff --git a/lib/color.rb b/lib/color.rb deleted file mode 100644 index 4723804e5f8..00000000000 --- a/lib/color.rb +++ /dev/null @@ -1,31 +0,0 @@ -module Color - extend self - - def colorize(text, color_code) - "\033[#{color_code}#{text}\033[0m" - end - - def red(text) - colorize(text, "31m") - end - - def green(text) - colorize(text, "32m") - end - - def yellow(text) - colorize(text, "93m") - end - - def command(string) - `#{string}` - if $?.to_i > 0 - puts red " == #{string} - FAIL" - puts red " == Error during configure" - exit - else - puts green " == #{string} - OK" - end - end -end - diff --git a/lib/file_size_validator.rb b/lib/file_size_validator.rb index 611e584f14f..42970c1be59 100644 --- a/lib/file_size_validator.rb +++ b/lib/file_size_validator.rb @@ -1,6 +1,6 @@ class FileSizeValidator < ActiveModel::EachValidator - MESSAGES = { :is => :wrong_size, :minimum => :size_too_small, :maximum => :size_too_big }.freeze - CHECKS = { :is => :==, :minimum => :>=, :maximum => :<= }.freeze + MESSAGES = { is: :wrong_size, minimum: :size_too_small, maximum: :size_too_big }.freeze + CHECKS = { is: :==, minimum: :>=, maximum: :<= }.freeze DEFAULT_TOKENIZER = lambda { |value| value.split(//) } RESERVED_OPTIONS = [:minimum, :maximum, :within, :is, :tokenizer, :too_short, :too_long] diff --git a/lib/gitlab/encode.rb b/lib/gitlab/encode.rb index 0787434b3af..7e37442ea32 100644 --- a/lib/gitlab/encode.rb +++ b/lib/gitlab/encode.rb @@ -19,7 +19,7 @@ module Gitlab # if message is not utf-8 encoding, convert it if detect[:encoding] message.force_encoding(detect[:encoding]) - message.encode!("utf-8", detect[:encoding], :undef => :replace, :replace => "", :invalid => :replace) + message.encode!("utf-8", detect[:encoding], undef: :replace, replace: "", invalid: :replace) end # ensure message encoding is utf8 diff --git a/lib/gitlab/gitolite.rb b/lib/gitlab/gitolite.rb index 7b80d4a836a..e82f9e62307 100644 --- a/lib/gitlab/gitolite.rb +++ b/lib/gitlab/gitolite.rb @@ -137,7 +137,7 @@ module Gitlab owner_name = repo.permissions[0]["RW+"][""][0] raise StandardError if owner_name.blank? rescue => ex - puts "Cant determine gitolite-admin owner".red + puts "Can't determine gitolite-admin owner".red raise StandardError end diff --git a/lib/gitlab/graph_commit.rb b/lib/gitlab/graph_commit.rb new file mode 100644 index 00000000000..b9859d79274 --- /dev/null +++ b/lib/gitlab/graph_commit.rb @@ -0,0 +1,183 @@ +require "grit" + +module Gitlab + class GraphCommit + attr_accessor :time, :space + attr_accessor :refs + + def self.to_graph(project) + @repo = project.repo + commits = Grit::Commit.find_all(@repo, nil, {max_count: 650}) + + ref_cache = {} + + commits.map! {|c| GraphCommit.new(Commit.new(c))} + commits.each { |commit| commit.add_refs(ref_cache, @repo) } + + days = GraphCommit.index_commits(commits) + @days_json = days.compact.collect{|d| [d.day, d.strftime("%b")] }.to_json + @commits_json = commits.map(&:to_graph_hash).to_json + + return @days_json, @commits_json + end + + # Method is adding time and space on the + # list of commits. As well as returns date list + # corelated with time set on commits. + # + # @param [Array<GraphCommit>] comits to index + # + # @return [Array<TimeDate>] list of commit dates corelated with time on commits + def self.index_commits(commits) + days, heads = [], [] + map = {} + + commits.reverse.each_with_index do |c,i| + c.time = i + days[i] = c.committed_date + map[c.id] = c + heads += c.refs unless c.refs.nil? + end + + heads.select!{|h| h.is_a? Grit::Head or h.is_a? Grit::Remote} + # sort heads so the master is top and current branches are closer + heads.sort! do |a,b| + if a.name == "master" + -1 + elsif b.name == "master" + 1 + else + b.commit.committed_date <=> a.commit.committed_date + end + end + + @_reserved = {} + days.each_index do |i| + @_reserved[i] = [] + end + + heads.each do |h| + if map.include? h.commit.id then + place_chain(map[h.commit.id], map) + end + end + days + end + + # Add space mark on commit and its parents + # + # @param [GraphCommit] the commit object. + # @param [Hash<String,GraphCommit>] map of commits + def self.place_chain(commit, map, parent_time = nil) + leaves = take_left_leaves(commit, map) + if leaves.empty? then + return + end + space = find_free_space(leaves.last.time..leaves.first.time) + leaves.each{|l| l.space = space} + # and mark it as reserved + min_time = leaves.last.time + parents = leaves.last.parents.collect + parents.each do |p| + if map.include? p.id then + parent = map[p.id] + if parent.time < min_time then + min_time = parent.time + end + end + end + if parent_time.nil? then + max_time = leaves.first.time + else + max_time = parent_time - 1 + end + mark_reserved(min_time..max_time, space) + # Visit branching chains + leaves.each do |l| + parents = l.parents.collect + .select{|p| map.include? p.id and map[p.id].space == 0} + for p in parents + place_chain(map[p.id], map, l.time) + end + end + end + + def self.mark_reserved(time_range, space) + for day in time_range + @_reserved[day].push(space) + end + end + + def self.find_free_space(time_range) + reserved = [] + for day in time_range + reserved += @_reserved[day] + end + space = 1 + while reserved.include? space do + space += 1 + end + space + end + + # Takes most left subtree branch of commits + # which don't have space mark yet. + # + # @param [GraphCommit] the commit object. + # @param [Hash<String,GraphCommit>] map of commits + # + # @return [Array<GraphCommit>] list of branch commits + def self.take_left_leaves(commit, map) + leaves = [] + leaves.push(commit) if commit.space == 0 + while true + parent = commit.parents.collect + .select{|p| map.include? p.id and map[p.id].space == 0} + if parent.count == 0 then + return leaves + else + commit = map[parent.first.id] + leaves.push(commit) + end + end + end + + + def initialize(commit) + @_commit = commit + @time = -1 + @space = 0 + end + + def method_missing(m, *args, &block) + @_commit.send(m, *args, &block) + end + + def to_graph_hash + h = {} + h[:parents] = self.parents.collect do |p| + [p.id,0,0] + end + h[:author] = Gitlab::Encode.utf8(author.name) + h[:time] = time + h[:space] = space + h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil? + h[:id] = sha + h[:date] = date + h[:message] = Gitlab::Encode.utf8(message) + h[:login] = author.email + h + end + + def add_refs(ref_cache, repo) + if ref_cache.empty? + repo.refs.each do |ref| + ref_cache[ref.commit.id] ||= [] + ref_cache[ref.commit.id] << ref + end + end + @refs = ref_cache[@_commit.id] if ref_cache.include?(@_commit.id) + @refs ||= [] + end + end +end diff --git a/lib/gitlab/logger.rb b/lib/gitlab/logger.rb index aff13baf67b..c3a19e71c10 100644 --- a/lib/gitlab/logger.rb +++ b/lib/gitlab/logger.rb @@ -10,6 +10,7 @@ module Gitlab def self.read_latest path = Rails.root.join("log/githost.log") + self.build unless File.exist?(path) logs = File.read(path).split("\n") end diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb new file mode 100644 index 00000000000..75fa835d502 --- /dev/null +++ b/lib/gitlab/markdown.rb @@ -0,0 +1,107 @@ +module Gitlab + # Custom parser for Gitlab-flavored Markdown + # + # It replaces references in the text with links to the appropriate items in Gitlab. + # + # Supported reference formats are: + # * @foo for team members + # * #123 for issues + # * !123 for merge requests + # * $123 for snippets + # * 123456 for commits + # + # Examples + # + # >> m = Markdown.new(...) + # + # >> m.parse("Hey @david, can you fix this?") + # => "Hey <a href="/gitlab/team_members/1">@david</a>, can you fix this?" + # + # >> m.parse("Commit 35d5f7c closes #1234") + # => "Commit <a href="/gitlab/commits/35d5f7c">35d5f7c</a> closes <a href="/gitlab/issues/1234">#1234</a>" + class Markdown + include Rails.application.routes.url_helpers + include ActionView::Helpers + + REFERENCE_PATTERN = %r{ + ([^\w&;])? # Prefix (1) + ( # Reference (2) + @([\w\._]+) # User name (3) + |[#!$](\d+) # Issue/MR/Snippet ID (4) + |([\h]{6,40}) # Commit ID (5) + ) + ([^\w&;])? # Suffix (6) + }x.freeze + + attr_reader :html_options + + def initialize(project, html_options = {}) + @project = project + @html_options = html_options + end + + def parse(text) + text.gsub(REFERENCE_PATTERN) do |match| + prefix = $1 || '' + reference = $2 + identifier = $3 || $4 || $5 + suffix = $6 || '' + + if ref_link = reference_link(reference, identifier) + prefix + ref_link + suffix + else + match + end + end + end + + private + + # Private: Dispatches to a dedicated processing method based on reference + # + # reference - Object reference ("@1234", "!567", etc.) + # identifier - Object identifier (Issue ID, SHA hash, etc.) + # + # Returns string rendered by the processing method + def reference_link(reference, identifier) + case reference + when /^@/ then reference_user(identifier) + when /^#/ then reference_issue(identifier) + when /^!/ then reference_merge_request(identifier) + when /^\$/ then reference_snippet(identifier) + when /^\h/ then reference_commit(identifier) + end + end + + def reference_user(identifier) + if user = @project.users.where(name: identifier).first + member = @project.users_projects.where(user_id: user).first + link_to("@#{identifier}", project_team_member_path(@project, member), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}")) if member + end + end + + def reference_issue(identifier) + if issue = @project.issues.where(id: identifier).first + link_to("##{identifier}", project_issue_path(@project, issue), html_options.merge(title: "Issue: #{issue.title}", class: "gfm gfm-issue #{html_options[:class]}")) + end + end + + def reference_merge_request(identifier) + if merge_request = @project.merge_requests.where(id: identifier).first + link_to("!#{identifier}", project_merge_request_path(@project, merge_request), html_options.merge(title: "Merge Request: #{merge_request.title}", class: "gfm gfm-merge_request #{html_options[:class]}")) + end + end + + def reference_snippet(identifier) + if snippet = @project.snippets.where(id: identifier).first + link_to("$#{identifier}", project_snippet_path(@project, snippet), html_options.merge(title: "Snippet: #{snippet.title}", class: "gfm gfm-snippet #{html_options[:class]}")) + end + end + + def reference_commit(identifier) + if commit = @project.commit(identifier) + link_to(identifier, project_commit_path(@project, id: commit.id), html_options.merge(title: "Commit: #{commit.author_name} - #{CommitDecorator.new(commit).title}", class: "gfm gfm-commit #{html_options[:class]}")) + end + end + end +end diff --git a/lib/graph_commit.rb b/lib/graph_commit.rb deleted file mode 100644 index 269378e8acc..00000000000 --- a/lib/graph_commit.rb +++ /dev/null @@ -1,181 +0,0 @@ -require "grit" - -class GraphCommit - attr_accessor :time, :space - attr_accessor :refs - - def self.to_graph(project) - @repo = project.repo - commits = Grit::Commit.find_all(@repo, nil, {:max_count => 650}) - - ref_cache = {} - - commits.map! {|c| GraphCommit.new(Commit.new(c))} - commits.each { |commit| commit.add_refs(ref_cache, @repo) } - - days = GraphCommit.index_commits(commits) - @days_json = days.compact.collect{|d| [d.day, d.strftime("%b")] }.to_json - @commits_json = commits.map(&:to_graph_hash).to_json - - return @days_json, @commits_json - end - - # Method is adding time and space on the - # list of commits. As well as returns date list - # corelated with time set on commits. - # - # @param [Array<GraphCommit>] comits to index - # - # @return [Array<TimeDate>] list of commit dates corelated with time on commits - def self.index_commits(commits) - days, heads = [], [] - map = {} - - commits.reverse.each_with_index do |c,i| - c.time = i - days[i] = c.committed_date - map[c.id] = c - heads += c.refs unless c.refs.nil? - end - - heads.select!{|h| h.is_a? Grit::Head or h.is_a? Grit::Remote} - # sort heads so the master is top and current branches are closer - heads.sort! do |a,b| - if a.name == "master" - -1 - elsif b.name == "master" - 1 - else - b.commit.committed_date <=> a.commit.committed_date - end - end - - @_reserved = {} - days.each_index do |i| - @_reserved[i] = [] - end - - heads.each do |h| - if map.include? h.commit.id then - place_chain(map[h.commit.id], map) - end - end - days - end - - # Add space mark on commit and its parents - # - # @param [GraphCommit] the commit object. - # @param [Hash<String,GraphCommit>] map of commits - def self.place_chain(commit, map, parent_time = nil) - leaves = take_left_leaves(commit, map) - if leaves.empty? then - return - end - space = find_free_space(leaves.last.time..leaves.first.time) - leaves.each{|l| l.space = space} - # and mark it as reserved - min_time = leaves.last.time - parents = leaves.last.parents.collect - parents.each do |p| - if map.include? p.id then - parent = map[p.id] - if parent.time < min_time then - min_time = parent.time - end - end - end - if parent_time.nil? then - max_time = leaves.first.time - else - max_time = parent_time - 1 - end - mark_reserved(min_time..max_time, space) - # Visit branching chains - leaves.each do |l| - parents = l.parents.collect - .select{|p| map.include? p.id and map[p.id].space == 0} - for p in parents - place_chain(map[p.id], map, l.time) - end - end - end - - def self.mark_reserved(time_range, space) - for day in time_range - @_reserved[day].push(space) - end - end - - def self.find_free_space(time_range) - reserved = [] - for day in time_range - reserved += @_reserved[day] - end - space = 1 - while reserved.include? space do - space += 1 - end - space - end - - # Takes most left subtree branch of commits - # which don't have space mark yet. - # - # @param [GraphCommit] the commit object. - # @param [Hash<String,GraphCommit>] map of commits - # - # @return [Array<GraphCommit>] list of branch commits - def self.take_left_leaves(commit, map) - leaves = [] - leaves.push(commit) if commit.space == 0 - while true - parent = commit.parents.collect - .select{|p| map.include? p.id and map[p.id].space == 0} - if parent.count == 0 then - return leaves - else - commit = map[parent.first.id] - leaves.push(commit) - end - end - end - - - def initialize(commit) - @_commit = commit - @time = -1 - @space = 0 - end - - def method_missing(m, *args, &block) - @_commit.send(m, *args, &block) - end - - def to_graph_hash - h = {} - h[:parents] = self.parents.collect do |p| - [p.id,0,0] - end - h[:author] = Gitlab::Encode.utf8(author.name) - h[:time] = time - h[:space] = space - h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil? - h[:id] = sha - h[:date] = date - h[:message] = Gitlab::Encode.utf8(message) - h[:login] = author.email - h - end - - def add_refs(ref_cache, repo) - if ref_cache.empty? - repo.refs.each do |ref| - ref_cache[ref.commit.id] ||= [] - ref_cache[ref.commit.id] << ref - end - end - @refs = ref_cache[@_commit.id] if ref_cache.include?(@_commit.id) - @refs ||= [] - end -end diff --git a/lib/post-receive-hook b/lib/hooks/post-receive index d38bd13e19d..d38bd13e19d 100755 --- a/lib/post-receive-hook +++ b/lib/hooks/post-receive diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb index 638c227cb20..30a807145ea 100644 --- a/lib/redcarpet/render/gitlab_html.rb +++ b/lib/redcarpet/render/gitlab_html.rb @@ -1,9 +1,23 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML + + attr_reader :template + alias_method :h, :template + + def initialize(template, options = {}) + @template = template + @project = @template.instance_variable_get("@project") + super options + end + def block_code(code, language) if Pygments::Lexer.find(language) - Pygments.highlight(code, :lexer => language, :options => {:encoding => 'utf-8'}) + Pygments.highlight(code, lexer: language, options: {encoding: 'utf-8'}) else - Pygments.highlight(code, :options => {:encoding => 'utf-8'}) + Pygments.highlight(code, options: {encoding: 'utf-8'}) end end + + def postprocess(full_document) + h.gfm(full_document) + end end diff --git a/lib/tasks/dev/repo.rake b/lib/tasks/dev/repo.rake deleted file mode 100644 index 7b389a5535b..00000000000 --- a/lib/tasks/dev/repo.rake +++ /dev/null @@ -1,26 +0,0 @@ -namespace :dev do - desc "Prepare for development (run dev_user.sh first)" - task :repos => :environment do - key = `sudo -u gitlabdev -H cat /home/gitlabdev/.ssh/id_rsa.pub` - raise "\n *** Run ./lib/tasks/dev/user.sh first *** \n" if key.empty? - Key.create(:user_id => User.first, :key => key, :title => "gitlabdev") - - puts "\n *** Clone diaspora from github" - `sudo -u gitlabdev -H sh -c "cd /home/gitlabdev; git clone git://github.com/diaspora/diaspora.git /home/gitlabdev/diaspora"` - - puts "\n *** Push diaspora source to gitlab" - `sudo -u gitlabdev -H sh -c "cd /home/gitlabdev/diaspora; git remote add local git@localhost:diaspora.git; git push local master; git push local --tags; git checkout -b api origin/api; git push local api; git checkout -b heroku origin/heroku; git push local heroku"` - - puts "\n *** Clone rails from github" - `sudo -u gitlabdev -H sh -c "cd /home/gitlabdev; git clone git://github.com/rails/rails.git /home/gitlabdev/rails"` - - puts "\n *** Push rails source to gitlab" - `sudo -u gitlabdev -H sh -c "cd /home/gitlabdev/rails; git remote add local git@localhost:ruby_on_rails.git; git push local master; git push local --tags"` - - puts "\n *** Clone rubinius from github" - `sudo -u gitlabdev -H sh -c "cd /home/gitlabdev; git clone git://github.com/rubinius/rubinius.git /home/gitlabdev/rubinius"` - - puts "\n *** Push rubinius source to gitlab" - `sudo -u gitlabdev -H sh -c "cd /home/gitlabdev/rubinius; git remote add local git@localhost:rubinius.git; git push local master; git push local --tags"` - end -end diff --git a/lib/tasks/dev/user.sh b/lib/tasks/dev/user.sh deleted file mode 100755 index d6b20df2ef2..00000000000 --- a/lib/tasks/dev/user.sh +++ /dev/null @@ -1,7 +0,0 @@ -sudo adduser \ - --gecos 'gitlab dev user' \ - --disabled-password \ - --home /home/gitlabdev \ - gitlabdev - -sudo -i -u gitlabdev -H sh -c "ssh-keygen -t rsa" diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake index 014483d4e8c..d9053c232cd 100644 --- a/lib/tasks/gitlab/backup.rake +++ b/lib/tasks/gitlab/backup.rake @@ -121,7 +121,7 @@ namespace :gitlab do backup_path_repo = File.join(Gitlab.config.backup_path, "repositories") FileUtils.mkdir_p(backup_path_repo) until Dir.exists?(backup_path_repo) puts "Dumping repositories:" - project = Project.all.map { |n| [n.name,n.path_to_repo] } + project = Project.all.map { |n| [n.path,n.path_to_repo] } project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")] project.each do |project| print "- Dumping repository #{project.first}... " @@ -136,12 +136,18 @@ namespace :gitlab do task :repo_restore => :environment do backup_path_repo = File.join(Gitlab.config.backup_path, "repositories") puts "Restoring repositories:" - project = Project.all.map { |n| [n.name,n.path_to_repo] } + project = Project.all.map { |n| [n.path,n.path_to_repo] } project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")] project.each do |project| print "- Restoring repository #{project.first}... " FileUtils.rm_rf(project.second) if File.dirname(project.second) # delet old stuff if Kernel.system("cd #{File.dirname(project.second)} > /dev/null 2>&1 && git clone --bare #{backup_path_repo}/#{project.first}.bundle #{project.first}.git > /dev/null 2>&1") + permission_commands = [ + "sudo chmod -R g+rwX #{Gitlab.config.git_base_path}", + "sudo chown -R #{Gitlab.config.ssh_user}:#{Gitlab.config.ssh_user} #{Gitlab.config.git_base_path}", + "sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive" + ] + permission_commands.each { |command| Kernel.system(command) } puts "[DONE]".green else puts "[FAILED]".red diff --git a/lib/tasks/gitlab/setup.rake b/lib/tasks/gitlab/setup.rake index d60e73e9ac3..49c86461c0b 100644 --- a/lib/tasks/gitlab/setup.rake +++ b/lib/tasks/gitlab/setup.rake @@ -1,7 +1,11 @@ namespace :gitlab do namespace :app do desc "GITLAB | Setup production application" - task :setup => ['db:setup', 'db:seed_fu', 'gitlab:app:enable_automerge'] + task :setup => [ + 'db:setup', + 'db:seed_fu', + 'gitlab:app:enable_automerge' + ] end end diff --git a/lib/tasks/gitlab/status.rake b/lib/tasks/gitlab/status.rake index ac712234b27..02d27d4bbcc 100644 --- a/lib/tasks/gitlab/status.rake +++ b/lib/tasks/gitlab/status.rake @@ -2,7 +2,7 @@ namespace :gitlab do namespace :app do desc "GITLAB | Check gitlab installation status" task :status => :environment do - puts "Starting diagnostic" + puts "Starting diagnostic".yellow git_base_path = Gitlab.config.git_base_path print "config/database.yml............" @@ -49,14 +49,43 @@ namespace :gitlab do end print "UMASK for .gitolite.rc is 0007? ............" - unless open("#{git_base_path}/../.gitolite.rc").grep(/REPO_UMASK = 0007/).empty? + unless open("#{git_base_path}/../.gitolite.rc").grep(/UMASK([ \t]*)=([ \t>]*)0007/).empty? puts "YES".green else puts "NO".red return end - puts "\nFinished" + gitolite_hooks_path = File.join("/home", Gitlab.config.ssh_user, "share", "gitolite", "hooks", "common") + gitlab_hook_files = ['post-receive'] + gitlab_hook_files.each do |file_name| + dest = File.join(gitolite_hooks_path, file_name) + print "#{dest} exists? ............" + if File.exists?(dest) + puts "YES".green + else + puts "NO".red + return + end + end + + + if Project.count > 0 + puts "Validating projects repositories:".yellow + Project.find_each(:batch_size => 100) do |project| + print "#{project.name}....." + hook_file = File.join(project.path_to_repo, 'hooks','post-receive') + + unless File.exists?(hook_file) + puts "post-receive file missing".red + next + end + + puts "post-reveice file ok".green + end + end + + puts "\nFinished".blue end end end diff --git a/lib/tasks/gitlab/update_hooks.rake b/lib/tasks/gitlab/update_hooks.rake deleted file mode 100644 index 44e1617e58f..00000000000 --- a/lib/tasks/gitlab/update_hooks.rake +++ /dev/null @@ -1,19 +0,0 @@ -namespace :gitlab do - namespace :gitolite do - desc "GITLAB | Rewrite hooks for repos" - task :update_hooks => :environment do - puts "Starting Projects" - Project.find_each(:batch_size => 100) do |project| - begin - if project.commit - project.write_hooks - print ".".green - end - rescue Exception => e - print e.message.red - end - end - puts "\nDone with projects" - end - end -end diff --git a/lib/tasks/gitlab/write_hook.rake b/lib/tasks/gitlab/write_hook.rake new file mode 100644 index 00000000000..098331b8cd7 --- /dev/null +++ b/lib/tasks/gitlab/write_hook.rake @@ -0,0 +1,23 @@ +namespace :gitlab do + namespace :gitolite do + desc "GITLAB | Write GITLAB hook for gitolite" + task :write_hooks => :environment do + gitolite_hooks_path = File.join("/home", Gitlab.config.ssh_user, "share", "gitolite", "hooks", "common") + gitlab_hooks_path = Rails.root.join("lib", "hooks") + + gitlab_hook_files = ['post-receive'] + + gitlab_hook_files.each do |file_name| + source = File.join(gitlab_hooks_path, file_name) + dest = File.join(gitolite_hooks_path, file_name) + + puts "sudo -u root cp #{source} #{dest}".yellow + `sudo -u root cp #{source} #{dest}` + + puts "sudo -u root chown git:git #{dest}".yellow + `sudo -u root chown git:git #{dest}` + end + end + end +end + diff --git a/public/404.html b/public/404.html index d4b26fe439c..3e56e52cc18 100644 --- a/public/404.html +++ b/public/404.html @@ -7,7 +7,7 @@ <body> <h1>404</h1> - <div class="alert-message block-message error"> + <div> <h2>The page you were looking for doesn't exist.</h2> <p>You may have mistyped the address or the page may have moved.</p> </div> diff --git a/public/422.html b/public/422.html index a0a0a244105..b6c37ac5386 100644 --- a/public/422.html +++ b/public/422.html @@ -8,7 +8,7 @@ <body> <!-- This file lives in public/422.html --> <h1>422</h1> - <div class="alert-message block-message error"> + <div> <h2>The change you wanted was rejected.</h2> <p>Maybe you tried to change something you didn't have access to.</p> </div> diff --git a/public/500.html b/public/500.html index 2868de5e686..3be1cc259c0 100644 --- a/public/500.html +++ b/public/500.html @@ -8,7 +8,7 @@ <body> <!-- This file lives in public/500.html --> <h1>500</h1> - <div class="alert-message block-message error"> + <div> <h2>We're sorry, but something went wrong.</h2> <p>We've been notified about this issue and we'll take a look at it shortly.</p> </div> diff --git a/resque.sh b/resque.sh index ce7c944b735..ab67c650805 100755 --- a/resque.sh +++ b/resque.sh @@ -1,2 +1,2 @@ mkdir -p tmp/pids -bundle exec rake environment resque:work QUEUE=post_receive,mailer RAILS_ENV=production PIDFILE=tmp/pids/resque_worker.pid BACKGROUND=yes +bundle exec rake environment resque:work QUEUE=post_receive,mailer,system_hook RAILS_ENV=production PIDFILE=tmp/pids/resque_worker.pid BACKGROUND=yes diff --git a/resque_dev.sh b/resque_dev.sh index 9df4dc1d087..b09cfd9e383 100755 --- a/resque_dev.sh +++ b/resque_dev.sh @@ -1 +1 @@ -bundle exec rake environment resque:work QUEUE=* VVERBOSE=1 +bundle exec rake environment resque:work QUEUE=post_receive,mailer,system_hook VVERBOSE=1 diff --git a/spec/api/projects_spec.rb b/spec/api/projects_spec.rb deleted file mode 100644 index 9998ee509bf..00000000000 --- a/spec/api/projects_spec.rb +++ /dev/null @@ -1,94 +0,0 @@ -require 'spec_helper' - -describe Gitlab::API do - let(:user) { Factory :user } - let!(:project) { Factory :project, :owner => user } - let!(:snippet) { Factory :snippet, :author => user, :project => project, :title => 'example' } - before { project.add_access(user, :read) } - - describe "GET /projects" do - it "should return authentication error" do - get "#{api_prefix}/projects" - response.status.should == 401 - end - - describe "authenticated GET /projects" do - it "should return an array of projects" do - get "#{api_prefix}/projects?private_token=#{user.private_token}" - response.status.should == 200 - json_response.should be_an Array - json_response.first['name'].should == project.name - json_response.first['owner']['email'].should == user.email - end - end - end - - describe "GET /projects/:id" do - it "should return a project by id" do - get "#{api_prefix}/projects/#{project.code}?private_token=#{user.private_token}" - response.status.should == 200 - json_response['name'].should == project.name - json_response['owner']['email'].should == user.email - end - end - - describe "GET /projects/:id/repository/branches" do - it "should return an array of project branches" do - get "#{api_prefix}/projects/#{project.code}/repository/branches?private_token=#{user.private_token}" - response.status.should == 200 - json_response.should be_an Array - json_response.first['name'].should == project.repo.heads.sort_by(&:name).first.name - end - end - - describe "GET /projects/:id/repository/tags" do - it "should return an array of project tags" do - get "#{api_prefix}/projects/#{project.code}/repository/tags?private_token=#{user.private_token}" - response.status.should == 200 - json_response.should be_an Array - json_response.first['name'].should == project.repo.tags.sort_by(&:name).reverse.first.name - end - end - - describe "GET /projects/:id/snippets/:snippet_id" do - it "should return a project snippet" do - get "#{api_prefix}/projects/#{project.code}/snippets/#{snippet.id}?private_token=#{user.private_token}" - response.status.should == 200 - json_response['title'].should == snippet.title - end - end - - describe "POST /projects/:id/snippets" do - it "should create a new project snippet" do - post "#{api_prefix}/projects/#{project.code}/snippets?private_token=#{user.private_token}", - :title => 'api test', :file_name => 'sample.rb', :code => 'test' - response.status.should == 201 - json_response['title'].should == 'api test' - end - end - - describe "PUT /projects/:id/snippets" do - it "should update an existing project snippet" do - put "#{api_prefix}/projects/#{project.code}/snippets/#{snippet.id}?private_token=#{user.private_token}", - :code => 'updated code' - response.status.should == 200 - json_response['title'].should == 'example' - snippet.reload.content.should == 'updated code' - end - end - - describe "DELETE /projects/:id/snippets/:snippet_id" do - it "should delete existing project snippet" do - expect { - delete "#{api_prefix}/projects/#{project.code}/snippets/#{snippet.id}?private_token=#{user.private_token}" - }.should change { Snippet.count }.by(-1) - end - end - - describe "GET /projects/:id/snippets/:snippet_id/raw" do - it "should get a raw project snippet" do - get "#{api_prefix}/projects/#{project.code}/snippets/#{snippet.id}/raw?private_token=#{user.private_token}" - response.status.should == 200 - end - end -end diff --git a/spec/factories.rb b/spec/factories.rb index ea8c7aef0e2..ab2ca4687da 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -7,6 +7,12 @@ Factory.add(:project, Project) do |obj| obj.code = 'LGT' end +Factory.add(:project_without_owner, Project) do |obj| + obj.name = Faker::Internet.user_name + obj.path = 'gitlabhq' + obj.code = 'LGT' +end + Factory.add(:public_project, Project) do |obj| obj.name = Faker::Internet.user_name obj.path = 'gitlabhq' @@ -60,7 +66,11 @@ Factory.add(:key, Key) do |obj| obj.key = File.read(File.join(Rails.root, "db", "pkey.example")) end -Factory.add(:web_hook, WebHook) do |obj| +Factory.add(:project_hook, ProjectHook) do |obj| + obj.url = Faker::Internet.uri("http") +end + +Factory.add(:system_hook, SystemHook) do |obj| obj.url = Faker::Internet.uri("http") end diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb new file mode 100644 index 00000000000..9a2df31479c --- /dev/null +++ b/spec/helpers/application_helper_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' + +describe ApplicationHelper do + describe "gravatar_icon" do + let(:user_email) { 'user@email.com' } + + it "should return a generic avatar path when Gravatar is disabled" do + Gitlab.config.stub(:disable_gravatar?).and_return(true) + gravatar_icon(user_email).should == 'no_avatar.png' + end + + it "should return a generic avatar path when email is blank" do + gravatar_icon('').should == 'no_avatar.png' + end + + it "should use SSL when appropriate" do + stub!(:request).and_return(double(:ssl? => true)) + gravatar_icon(user_email).should match('https://secure.gravatar.com') + end + + it "should accept a custom size" do + stub!(:request).and_return(double(:ssl? => false)) + gravatar_icon(user_email, 64).should match(/\?s=64/) + end + end +end diff --git a/spec/helpers/commit_helper_spec.rb b/spec/helpers/commit_helper_spec.rb deleted file mode 100644 index 747a28a35b9..00000000000 --- a/spec/helpers/commit_helper_spec.rb +++ /dev/null @@ -1,67 +0,0 @@ -require "spec_helper" -include Haml::Helpers - -describe CommitsHelper do - - before do - @project = Factory :project - @other_project = Factory :project, :path => "OtherPath", :code => "OtherCode" - @fake_user = Factory :user - @valid_issue = Factory :issue, :assignee => @fake_user, :author => @fake_user, :project => @project - @invalid_issue = Factory :issue, :assignee => @fake_user, :author => @fake_user, :project => @other_project - end - - it "should provides return message untouched if no issue number present" do - message = "Dummy message without issue number" - - commit_msg_with_link_to_issues(@project, message).should eql message - end - - it "should returns message handled by preserve" do - message = "My brand new - Commit on multiple - lines !" - - #\n are converted to 
 as specified in preserve_rspec - expected = "My brand new
 Commit on multiple
 lines !" - - commit_msg_with_link_to_issues(@project, message).should eql expected - end - - it "should returns empty string if message undefined" do - commit_msg_with_link_to_issues(@project, nil).should eql '' - end - - it "should returns link_to issue for one valid issue in message" do - issue_id = @valid_issue.id - message = "One commit message ##{issue_id}" - expected = "One commit message <a href=\"/#{@project.code}/issues/#{issue_id}\">##{issue_id}</a>" - - commit_msg_with_link_to_issues(@project, message).should eql expected - end - - it "should returns message untouched for one invalid issue in message" do - issue_id = @invalid_issue.id - message = "One commit message ##{issue_id}" - - commit_msg_with_link_to_issues(@project, message).should eql message - end - - it "should handle multiple issue references in commit message" do - issue_id = @valid_issue.id - invalid_issue_id = @invalid_issue.id - - message = "One big commit message with a valid issue ##{issue_id} and an invalid one ##{invalid_issue_id}. - We reference valid ##{issue_id} multiple times (##{issue_id}) as the invalid ##{invalid_issue_id} is also - referenced another time (##{invalid_issue_id})" - - expected = "One big commit message with a valid issue <a href=\"/#{@project.code}/issues/#{issue_id}\">##{issue_id}</a>"+ - " and an invalid one ##{invalid_issue_id}.
 "+ - "We reference valid <a href=\"/#{@project.code}/issues/#{issue_id}\">##{issue_id}</a> multiple times "+ - "(<a href=\"/#{@project.code}/issues/#{issue_id}\">##{issue_id}</a>) "+ - "as the invalid ##{invalid_issue_id} is also
 referenced another time (##{invalid_issue_id})" - - commit_msg_with_link_to_issues(@project, message).should eql expected - end - -end
\ No newline at end of file diff --git a/spec/helpers/gitlab_flavored_markdown_spec.rb b/spec/helpers/gitlab_flavored_markdown_spec.rb new file mode 100644 index 00000000000..e147cb39375 --- /dev/null +++ b/spec/helpers/gitlab_flavored_markdown_spec.rb @@ -0,0 +1,232 @@ +require "spec_helper" + +describe GitlabMarkdownHelper do + before do + @project = Project.find_by_path("gitlabhq") || Factory(:project) + @commit = @project.repo.commits.first.parents.first + @commit = CommitDecorator.decorate(Commit.new(@commit)) + @other_project = Factory :project, path: "OtherPath", code: "OtherCode" + @fake_user = Factory :user, name: "fred" + end + + describe "#gfm" do + it "should return text if @project is not set" do + @project = nil + + gfm("foo").should == "foo" + end + + describe "referencing a commit" do + it "should link using a full id" do + gfm("Reverts changes from #{@commit.id}").should == "Reverts changes from #{link_to @commit.id, project_commit_path(@project, id: @commit.id), title: "Commit: #{@commit.author_name} - #{@commit.title}", class: "gfm gfm-commit "}" + end + + it "should link using a short id" do + gfm("Backported from #{@commit.id[0, 6]}").should == "Backported from #{link_to @commit.id[0, 6], project_commit_path(@project, id: @commit.id), title: "Commit: #{@commit.author_name} - #{@commit.title}", class: "gfm gfm-commit "}" + end + + it "should link with adjecent text" do + gfm("Reverted (see #{@commit.id})").should == "Reverted (see #{link_to @commit.id, project_commit_path(@project, id: @commit.id), title: "Commit: #{@commit.author_name} - #{@commit.title}", class: "gfm gfm-commit "})" + end + + it "should not link with an invalid id" do + gfm("What happened in 12345678?").should == "What happened in 12345678?" + end + end + + describe "referencing a team member" do + it "should link using a simple name" do + user = Factory :user, name: "barry" + @project.users << user + member = @project.users_projects.where(user_id: user).first + + gfm("@#{user.name} you are right").should == "#{link_to "@#{user.name}", project_team_member_path(@project, member), class: "gfm gfm-team_member "} you are right" + end + + it "should link using a name with dots" do + user = Factory :user, name: "alphA.Beta" + @project.users << user + member = @project.users_projects.where(user_id: user).first + + gfm("@#{user.name} you are right").should == "#{link_to "@#{user.name}", project_team_member_path(@project, member), class: "gfm gfm-team_member "} you are right" + end + + it "should link using name with underscores" do + user = Factory :user, name: "ping_pong_king" + @project.users << user + member = @project.users_projects.where(user_id: user).first + + gfm("@#{user.name} you are right").should == "#{link_to "@#{user.name}", project_team_member_path(@project, member), class: "gfm gfm-team_member "} you are right" + end + + it "should link with adjecent text" do + user = Factory.create(:user, name: "ace") + @project.users << user + member = @project.users_projects.where(user_id: user).first + + gfm("Mail the Admin (@#{user.name})").should == "Mail the Admin (#{link_to "@#{user.name}", project_team_member_path(@project, member), class: "gfm gfm-team_member "})" + end + + it "should add styles" do + user = Factory :user, name: "barry" + @project.users << user + gfm("@#{user.name} you are right").should have_selector(".gfm.gfm-team_member") + end + + it "should not link using a bogus name" do + gfm("What hapened to @foo?").should == "What hapened to @foo?" + end + end + + describe "referencing an issue" do + before do + @issue = Factory :issue, assignee: @fake_user, author: @fake_user, project: @project + @invalid_issue = Factory :issue, assignee: @fake_user, author: @fake_user, project: @other_project + end + + it "should link using a correct id" do + gfm("Fixes ##{@issue.id}").should == "Fixes #{link_to "##{@issue.id}", project_issue_path(@project, @issue), title: "Issue: #{@issue.title}", class: "gfm gfm-issue "}" + end + + it "should link with adjecent text" do + gfm("This has already been discussed (see ##{@issue.id})").should == "This has already been discussed (see #{link_to "##{@issue.id}", project_issue_path(@project, @issue), title: "Issue: #{@issue.title}", class: "gfm gfm-issue "})" + end + + it "should add styles" do + gfm("Fixes ##{@issue.id}").should have_selector(".gfm.gfm-issue") + end + + it "should not link using an invalid id" do + gfm("##{@invalid_issue.id} has been marked duplicate of this").should == "##{@invalid_issue.id} has been marked duplicate of this" + end + end + + describe "referencing a merge request" do + before do + @merge_request = Factory :merge_request, assignee: @fake_user, author: @fake_user, project: @project + @invalid_merge_request = Factory :merge_request, assignee: @fake_user, author: @fake_user, project: @other_project + end + + it "should link using a correct id" do + gfm("Fixed in !#{@merge_request.id}").should == "Fixed in #{link_to "!#{@merge_request.id}", project_merge_request_path(@project, @merge_request), title: "Merge Request: #{@merge_request.title}", class: "gfm gfm-merge_request "}" + end + + it "should link with adjecent text" do + gfm("This has been fixed already (see !#{@merge_request.id})").should == "This has been fixed already (see #{link_to "!#{@merge_request.id}", project_merge_request_path(@project, @merge_request), title: "Merge Request: #{@merge_request.title}", class: "gfm gfm-merge_request "})" + end + + it "should add styles" do + gfm("Fixed in !#{@merge_request.id}").should have_selector(".gfm.gfm-merge_request") + end + + it "should not link using an invalid id" do + gfm("!#{@invalid_merge_request.id} violates our coding guidelines") + end + end + + describe "referencing a snippet" do + before do + @snippet = Factory.create(:snippet, + title: "Render asset to string", + author: @fake_user, + project: @project) + end + + it "should link using a correct id" do + gfm("Check out $#{@snippet.id}").should == "Check out #{link_to "$#{@snippet.id}", project_snippet_path(@project, @snippet), title: "Snippet: #{@snippet.title}", class: "gfm gfm-snippet "}" + end + + it "should link with adjecent text" do + gfm("I have created a snippet for that ($#{@snippet.id})").should == "I have created a snippet for that (#{link_to "$#{@snippet.id}", project_snippet_path(@project, @snippet), title: "Snippet: #{@snippet.title}", class: "gfm gfm-snippet "})" + end + + it "should add styles" do + gfm("Check out $#{@snippet.id}").should have_selector(".gfm.gfm-snippet") + end + + it "should not link using an invalid id" do + gfm("Don't use $1234").should == "Don't use $1234" + end + end + + it "should link to multiple things" do + user = Factory :user, name: "barry" + @project.users << user + member = @project.users_projects.where(user_id: user).first + + gfm("Let @#{user.name} fix the *mess* in #{@commit.id}").should == "Let #{link_to "@#{user.name}", project_team_member_path(@project, member), class: "gfm gfm-team_member "} fix the *mess* in #{link_to @commit.id, project_commit_path(@project, id: @commit.id), title: "Commit: #{@commit.author_name} - #{@commit.title}", class: "gfm gfm-commit "}" + end + + it "should not trip over other stuff", focus: true do + gfm("_Please_ *stop* 'helping' and all the other b*$#%' you do.").should == "_Please_ *stop* 'helping' and all the other b*$#%' you do." + end + + it "should not touch HTML entities" do + gfm("We'll accept good pull requests.").should == "We'll accept good pull requests." + end + + it "should forward HTML options to links" do + gfm("fixed in #{@commit.id}", class: "foo").should have_selector("a.foo") + end + end + + describe "#link_to_gfm" do + let(:issue1) { Factory :issue, assignee: @fake_user, author: @fake_user, project: @project } + let(:issue2) { Factory :issue, assignee: @fake_user, author: @fake_user, project: @project } + + it "should handle references nested in links with all the text" do + link_to_gfm("This should finally fix ##{issue1.id} and ##{issue2.id} for real", project_commit_path(@project, id: @commit.id)).should == "#{link_to "This should finally fix ", project_commit_path(@project, id: @commit.id)}#{link_to "##{issue1.id}", project_issue_path(@project, issue1), title: "Issue: #{issue1.title}", class: "gfm gfm-issue "}#{link_to " and ", project_commit_path(@project, id: @commit.id)}#{link_to "##{issue2.id}", project_issue_path(@project, issue2), title: "Issue: #{issue2.title}", class: "gfm gfm-issue "}#{link_to " for real", project_commit_path(@project, id: @commit.id)}" + end + + it "should forward HTML options" do + link_to_gfm("This should finally fix ##{issue1.id} for real", project_commit_path(@project, id: @commit.id), class: "foo").should have_selector(".foo") + end + end + + describe "#markdown" do + before do + @issue = Factory :issue, assignee: @fake_user, author: @fake_user, project: @project + @merge_request = Factory :merge_request, assignee: @fake_user, author: @fake_user, project: @project + @note = Factory.create(:note, + note: "Screenshot of the new feature", + project: @project, + noteable_id: @commit.id, + noteable_type: "Commit", + attachment: "screenshot123.jpg") + @snippet = Factory.create(:snippet, + title: "Render asset to string", + author: @fake_user, + project: @project) + + @other_user = Factory :user, name: "bill" + @project.users << @other_user + @member = @project.users_projects.where(user_id: @other_user).first + end + + it "should handle references in paragraphs" do + markdown("\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. #{@commit.id} Nam pulvinar sapien eget odio adipiscing at faucibus orci vestibulum.\n").should == "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. #{link_to @commit.id, project_commit_path(@project, id: @commit.id), title: "Commit: #{@commit.author_name} - #{@commit.title}", class: "gfm gfm-commit "} Nam pulvinar sapien eget odio adipiscing at faucibus orci vestibulum.</p>\n" + end + + it "should handle references in headers" do + markdown("\n# Working around ##{@issue.id} for now\n## Apply !#{@merge_request.id}").should == "<h1 id=\"toc_0\">Working around #{link_to "##{@issue.id}", project_issue_path(@project, @issue), title: "Issue: #{@issue.title}", class: "gfm gfm-issue "} for now</h1>\n\n<h2 id=\"toc_1\">Apply #{link_to "!#{@merge_request.id}", project_merge_request_path(@project, @merge_request), title: "Merge Request: #{@merge_request.title}", class: "gfm gfm-merge_request "}</h2>\n" + end + + it "should handle references in lists" do + markdown("\n* dark: ##{@issue.id}\n* light by @#{@other_user.name}\n").should == "<ul>\n<li>dark: #{link_to "##{@issue.id}", project_issue_path(@project, @issue), title: "Issue: #{@issue.title}", class: "gfm gfm-issue "}</li>\n<li>light by #{link_to "@#{@other_user.name}", project_team_member_path(@project, @member), class: "gfm gfm-team_member "}</li>\n</ul>\n" + end + + it "should handle references in <em>" do + markdown("Apply _!#{@merge_request.id}_ ASAP").should == "<p>Apply <em>#{link_to "!#{@merge_request.id}", project_merge_request_path(@project, @merge_request), title: "Merge Request: #{@merge_request.title}", class: "gfm gfm-merge_request "}</em> ASAP</p>\n" + end + + it "should leave code blocks untouched" do + markdown("\n some code from $#{@snippet.id}\n here too\n").should == "<div class=\"highlight\"><pre><span class=\"n\">some</span> <span class=\"n\">code</span> <span class=\"n\">from</span> $#{@snippet.id}\n<span class=\"n\">here</span> <span class=\"n\">too</span>\n</pre>\n</div>\n" + + markdown("\n```\nsome code from $#{@snippet.id}\nhere too\n```\n").should == "<div class=\"highlight\"><pre><span class=\"n\">some</span> <span class=\"n\">code</span> <span class=\"n\">from</span> $#{@snippet.id}\n<span class=\"n\">here</span> <span class=\"n\">too</span>\n</pre>\n</div>\n" + end + + it "should leave inline code untouched" do + markdown("\nDon't use `$#{@snippet.id}` here.\n").should == "<p>Don't use <code>$#{@snippet.id}</code> here.</p>\n" + end + end +end diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 4df771b97fe..93427ebfacd 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -4,7 +4,7 @@ describe Notify do include EmailSpec::Helpers include EmailSpec::Matchers - let(:recipient) { Factory.create(:user, :email => 'recipient@example.com') } + let(:recipient) { Factory.create(:user, email: 'recipient@example.com') } let(:project) { Factory.create(:project) } shared_examples 'a multiple recipients email' do @@ -15,7 +15,7 @@ describe Notify do describe 'for new users, the email' do let(:example_site_path) { root_path } - let(:new_user) { Factory.create(:user, :email => 'newguy@example.com') } + let(:new_user) { Factory.create(:user, email: 'newguy@example.com') } subject { Notify.new_user_email(new_user.id, new_user.password) } @@ -24,7 +24,7 @@ describe Notify do end it 'has the correct subject' do - should have_subject /Account was created for you/ + should have_subject /^gitlab \| Account was created for you$/ end it 'contains the new user\'s login name' do @@ -42,8 +42,8 @@ describe Notify do context 'for a project' do describe 'items that are assignable, the email' do - let(:assignee) { Factory.create(:user, :email => 'assignee@example.com') } - let(:previous_assignee) { Factory.create(:user, :name => 'Previous Assignee') } + let(:assignee) { Factory.create(:user, email: 'assignee@example.com') } + let(:previous_assignee) { Factory.create(:user, name: 'Previous Assignee') } shared_examples 'an assignee email' do it 'is sent to the assignee' do @@ -52,7 +52,7 @@ describe Notify do end context 'for issues' do - let(:issue) { Factory.create(:issue, :assignee => assignee, :project => project ) } + let(:issue) { Factory.create(:issue, assignee: assignee, project: project ) } describe 'that are new' do subject { Notify.new_issue_email(issue.id) } @@ -60,7 +60,7 @@ describe Notify do it_behaves_like 'an assignee email' it 'has the correct subject' do - should have_subject /New Issue was created/ + should have_subject /new issue ##{issue.id} \| #{issue.title} \| #{project.name}/ end it 'contains a link to the new issue' do @@ -76,7 +76,7 @@ describe Notify do it_behaves_like 'a multiple recipients email' it 'has the correct subject' do - should have_subject /changed issue/ + should have_subject /changed issue ##{issue.id} \| #{issue.title}/ end it 'contains the name of the previous assignee' do @@ -94,7 +94,7 @@ describe Notify do end context 'for merge requests' do - let(:merge_request) { Factory.create(:merge_request, :assignee => assignee, :project => project) } + let(:merge_request) { Factory.create(:merge_request, assignee: assignee, project: project) } describe 'that are new' do subject { Notify.new_merge_request_email(merge_request.id) } @@ -102,7 +102,7 @@ describe Notify do it_behaves_like 'an assignee email' it 'has the correct subject' do - should have_subject /new merge request/ + should have_subject /new merge request !#{merge_request.id}/ end it 'contains a link to the new merge request' do @@ -126,7 +126,7 @@ describe Notify do it_behaves_like 'a multiple recipients email' it 'has the correct subject' do - should have_subject /merge request changed/ + should have_subject /changed merge request !#{merge_request.id}/ end it 'contains the name of the previous assignee' do @@ -146,8 +146,8 @@ describe Notify do end context 'items that are noteable, the email for a note' do - let(:note_author) { Factory.create(:user, :name => 'author_name') } - let(:note) { Factory.create(:note, :project => project, :author => note_author) } + let(:note_author) { Factory.create(:user, name: 'author_name') } + let(:note) { Factory.create(:note, project: project, author: note_author) } before :each do Note.stub(:find).with(note.id).and_return(note) @@ -168,7 +168,7 @@ describe Notify do end describe 'on a project wall' do - let(:note_on_the_wall_path) { wall_project_path(project, :anchor => "note_#{note.id}") } + let(:note_on_the_wall_path) { wall_project_path(project, anchor: "note_#{note.id}") } subject { Notify.note_wall_email(recipient.id, note.id) } @@ -188,6 +188,8 @@ describe Notify do mock(:commit).tap do |commit| commit.stub(:id).and_return('fauxsha1') commit.stub(:project).and_return(project) + commit.stub(:short_id).and_return('fauxsha1') + commit.stub(:safe_message).and_return('some message') end end before(:each) { note.stub(:target).and_return(commit) } @@ -197,7 +199,7 @@ describe Notify do it_behaves_like 'a note email' it 'has the correct subject' do - should have_subject /note for commit/ + should have_subject /note for commit #{commit.short_id}/ end it 'contains a link to the commit' do @@ -206,8 +208,8 @@ describe Notify do end describe 'on a merge request' do - let(:merge_request) { Factory.create(:merge_request, :project => project) } - let(:note_on_merge_request_path) { project_merge_request_path(project, merge_request, :anchor => "note_#{note.id}") } + let(:merge_request) { Factory.create(:merge_request, project: project) } + let(:note_on_merge_request_path) { project_merge_request_path(project, merge_request, anchor: "note_#{note.id}") } before(:each) { note.stub(:noteable).and_return(merge_request) } subject { Notify.note_merge_request_email(recipient.id, note.id) } @@ -215,7 +217,7 @@ describe Notify do it_behaves_like 'a note email' it 'has the correct subject' do - should have_subject /note for merge request/ + should have_subject /note for merge request !#{merge_request.id}/ end it 'contains a link to the merge request note' do @@ -224,8 +226,8 @@ describe Notify do end describe 'on an issue' do - let(:issue) { Factory.create(:issue, :project => project) } - let(:note_on_issue_path) { project_issue_path(project, issue, :anchor => "note_#{note.id}") } + let(:issue) { Factory.create(:issue, project: project) } + let(:note_on_issue_path) { project_issue_path(project, issue, anchor: "note_#{note.id}") } before(:each) { note.stub(:noteable).and_return(issue) } subject { Notify.note_issue_email(recipient.id, note.id) } @@ -233,7 +235,7 @@ describe Notify do it_behaves_like 'a note email' it 'has the correct subject' do - should have_subject /note for issue #{issue.id}/ + should have_subject /note for issue ##{issue.id}/ end it 'contains a link to the issue note' do diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index a295e2860cc..188f09978a7 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -45,25 +45,25 @@ describe Event do @user = project.owner data = { - :before => "0000000000000000000000000000000000000000", - :after => "0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e", - :ref => "refs/heads/master", - :user_id => @user.id, - :user_name => @user.name, - :repository => { - :name => project.name, - :url => "localhost/rubinius", - :description => "", - :homepage => "localhost/rubinius", - :private => true + before: "0000000000000000000000000000000000000000", + after: "0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e", + ref: "refs/heads/master", + user_id: @user.id, + user_name: @user.name, + repository: { + name: project.name, + url: "localhost/rubinius", + description: "", + homepage: "localhost/rubinius", + private: true } } @event = Event.create( - :project => project, - :action => Event::Pushed, - :data => data, - :author_id => @user.id + project: project, + action: Event::Pushed, + data: data, + author_id: @user.id ) end diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index fbd4031fa0b..e9cbd72589a 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -20,9 +20,9 @@ describe Issue do end subject { Factory.create(:issue, - :author => Factory(:user), - :assignee => Factory(:user), - :project => Factory.create(:project)) } + author: Factory(:user), + assignee: Factory(:user), + project: Factory.create(:project)) } it { should be_valid } describe '#is_being_reassigned?' do @@ -42,10 +42,10 @@ describe Issue do end it 'returns false if the closed attribute has changed and is now false' do issue = Factory.create(:issue, - :closed => true, - :author => Factory(:user), - :assignee => Factory(:user), - :project => Factory.create(:project)) + closed: true, + author: Factory(:user), + assignee: Factory(:user), + project: Factory.create(:project)) issue.closed = false issue.is_being_closed?.should be_false end @@ -58,10 +58,10 @@ describe Issue do describe '#is_being_reopened?' do it 'returns true if the closed attribute has changed and is now false' do issue = Factory.create(:issue, - :closed => true, - :author => Factory(:user), - :assignee => Factory(:user), - :project => Factory.create(:project)) + closed: true, + author: Factory(:user), + assignee: Factory(:user), + project: Factory.create(:project)) issue.closed = false issue.is_being_reopened?.should be_true end @@ -78,9 +78,9 @@ describe Issue do let(:project) { Factory(:project) } subject { Factory.create(:issue, - :author => Factory(:user), - :assignee => Factory(:user), - :project => project) + author: Factory(:user), + assignee: Factory(:user), + project: project) } it "with no notes has a 0/0 score" do @@ -106,6 +106,14 @@ describe Issue do end end + describe ".search" do + let!(:issue) { Factory.create(:issue, title: "Searchable issue", + project: Factory.create(:project)) } + + it "matches by title" do + Issue.search('able').all.should == [issue] + end + end end # == Schema Information # diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index ac986ccebe3..c7ad08a1e06 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -21,17 +21,17 @@ describe MergeRequest do end it { Factory.create(:merge_request, - :author => Factory(:user), - :assignee => Factory(:user), - :project => Factory.create(:project)).should be_valid } + author: Factory(:user), + assignee: Factory(:user), + project: Factory.create(:project)).should be_valid } describe "plus 1" do let(:project) { Factory(:project) } subject { Factory.create(:merge_request, - :author => Factory(:user), - :assignee => Factory(:user), - :project => project) + author: Factory(:user), + assignee: Factory(:user), + project: project) } it "with no notes has a 0/0 score" do @@ -56,6 +56,15 @@ describe MergeRequest do subject.upvotes.should == 2 end end + + describe ".search" do + let!(:issue) { Factory.create(:issue, title: "Searchable issue", + project: Factory.create(:project)) } + + it "matches by title" do + Issue.search('able').all.should == [issue] + end + end end # == Schema Information # diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb index bb71ca990f0..e9acc4e2815 100644 --- a/spec/models/milestone_spec.rb +++ b/spec/models/milestone_spec.rb @@ -26,29 +26,38 @@ describe Milestone do end let(:project) { Factory :project } - let(:milestone) { Factory :milestone, :project => project } - let(:issue) { Factory :issue, :project => project } + let(:milestone) { Factory :milestone, project: project } + let(:issue) { Factory :issue, project: project } it { milestone.should be_valid } - describe "Issues" do - before do + describe "#percent_complete" do + it "should not count open issues" do milestone.issues << issue + milestone.percent_complete.should == 0 end - it { milestone.percent_complete.should == 0 } + it "should count closed issues" do + issue.update_attributes(closed: true) + milestone.issues << issue + milestone.percent_complete.should == 100 + end - it do - issue.update_attributes :closed => true + it "should recover from dividing by zero" do + milestone.issues.should_receive(:count).and_return(0) milestone.percent_complete.should == 100 end end - describe :expires_at do - before do - milestone.update_attributes :due_date => Date.today + 1.day + describe "#expires_at" do + it "should be nil when due_date is unset" do + milestone.update_attributes(due_date: nil) + milestone.expires_at.should be_nil end - it { milestone.expires_at.should_not be_nil } + it "should not be nil when due_date is set" do + milestone.update_attributes(due_date: Date.tomorrow) + milestone.expires_at.should be_present + end end end diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index f2dfcabcc87..c97b23cb4fa 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -14,7 +14,7 @@ describe Note do end it { Factory.create(:note, - :project => project).should be_valid } + project: project).should be_valid } describe "Scopes" do it "should have a today named scope that returns ..." do Note.today.where_values.should == ["created_at >= '#{Date.today}'"] @@ -44,9 +44,9 @@ describe Note do before do @note = Factory :note, - :project => project, - :noteable_id => commit.id, - :noteable_type => "Commit" + project: project, + noteable_id: commit.id, + noteable_type: "Commit" end it "should save a valid note" do @@ -58,10 +58,10 @@ describe Note do describe "Pre-line commit notes" do before do @note = Factory :note, - :project => project, - :noteable_id => commit.id, - :noteable_type => "Commit", - :line_code => "0_16_1" + project: project, + noteable_id: commit.id, + noteable_type: "Commit", + line_code: "0_16_1" end it "should save a valid note" do @@ -72,7 +72,7 @@ describe Note do describe '#create_status_change_note' do let(:project) { Factory.create(:project) } - let(:thing) { Factory.create(:issue, :project => project) } + let(:thing) { Factory.create(:issue, project: project) } let(:author) { Factory(:user) } let(:status) { 'new_status' } @@ -92,7 +92,7 @@ describe Note do describe :authorization do before do @p1 = project - @p2 = Factory :project, :code => "alien", :path => "gitlabhq_1" + @p2 = Factory :project, code: "alien", path: "gitlabhq_1" @u1 = Factory :user @u2 = Factory :user @u3 = Factory :user @@ -102,8 +102,8 @@ describe Note do describe :read do before do - @p1.users_projects.create(:user => @u2, :project_access => UsersProject::GUEST) - @p2.users_projects.create(:user => @u3, :project_access => UsersProject::GUEST) + @p1.users_projects.create(user: @u2, project_access: UsersProject::GUEST) + @p2.users_projects.create(user: @u3, project_access: UsersProject::GUEST) end it { @abilities.allowed?(@u1, :read_note, @p1).should be_false } @@ -113,8 +113,8 @@ describe Note do describe :write do before do - @p1.users_projects.create(:user => @u2, :project_access => UsersProject::DEVELOPER) - @p2.users_projects.create(:user => @u3, :project_access => UsersProject::DEVELOPER) + @p1.users_projects.create(user: @u2, project_access: UsersProject::DEVELOPER) + @p2.users_projects.create(user: @u3, project_access: UsersProject::DEVELOPER) end it { @abilities.allowed?(@u1, :write_note, @p1).should be_false } @@ -124,9 +124,9 @@ describe Note do describe :admin do before do - @p1.users_projects.create(:user => @u1, :project_access => UsersProject::REPORTER) - @p1.users_projects.create(:user => @u2, :project_access => UsersProject::MASTER) - @p2.users_projects.create(:user => @u3, :project_access => UsersProject::MASTER) + @p1.users_projects.create(user: @u1, project_access: UsersProject::REPORTER) + @p1.users_projects.create(user: @u2, project_access: UsersProject::MASTER) + @p2.users_projects.create(user: @u3, project_access: UsersProject::MASTER) end it { @abilities.allowed?(@u1, :admin_note, @p1).should be_false } diff --git a/spec/models/project_hooks_spec.rb b/spec/models/project_hooks_spec.rb index fcc969ceba5..129e3d61030 100644 --- a/spec/models/project_hooks_spec.rb +++ b/spec/models/project_hooks_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Project, "Hooks" do let(:project) { Factory :project } before do - @key = Factory :key, :user => project.owner + @key = Factory :key, user: project.owner @user = @key.user @key_id = @key.identifier end @@ -21,44 +21,44 @@ describe Project, "Hooks" do end end - describe "Web hooks" do + describe "Project hooks" do context "with no web hooks" do it "raises no errors" do lambda { - project.execute_web_hooks('oldrev', 'newrev', 'ref', @user) + project.execute_hooks('oldrev', 'newrev', 'ref', @user) }.should_not raise_error end end context "with web hooks" do before do - @webhook = Factory(:web_hook) - @webhook_2 = Factory(:web_hook) - project.web_hooks << [@webhook, @webhook_2] + @project_hook = Factory(:project_hook) + @project_hook_2 = Factory(:project_hook) + project.hooks << [@project_hook, @project_hook_2] end it "executes multiple web hook" do - @webhook.should_receive(:execute).once - @webhook_2.should_receive(:execute).once + @project_hook.should_receive(:execute).once + @project_hook_2.should_receive(:execute).once - project.execute_web_hooks('oldrev', 'newrev', 'refs/heads/master', @user) + project.execute_hooks('oldrev', 'newrev', 'refs/heads/master', @user) end end context "does not execute web hooks" do before do - @webhook = Factory(:web_hook) - project.web_hooks << [@webhook] + @project_hook = Factory(:project_hook) + project.hooks << [@project_hook] end it "when pushing a branch for the first time" do - @webhook.should_not_receive(:execute) - project.execute_web_hooks('00000000000000000000000000000000', 'newrev', 'refs/heads/master', @user) + @project_hook.should_not_receive(:execute) + project.execute_hooks('00000000000000000000000000000000', 'newrev', 'refs/heads/master', @user) end it "when pushing tags" do - @webhook.should_not_receive(:execute) - project.execute_web_hooks('oldrev', 'newrev', 'refs/tags/v1.0.0', @user) + @project_hook.should_not_receive(:execute) + project.execute_hooks('oldrev', 'newrev', 'refs/tags/v1.0.0', @user) end end diff --git a/spec/models/project_security_spec.rb b/spec/models/project_security_spec.rb index bd697af9652..baf6d4b68ea 100644 --- a/spec/models/project_security_spec.rb +++ b/spec/models/project_security_spec.rb @@ -12,7 +12,7 @@ describe Project do describe "read access" do before do - @p1.users_projects.create(:project => @p1, :user => @u2, :project_access => UsersProject::REPORTER) + @p1.users_projects.create(project: @p1, user: @u2, project_access: UsersProject::REPORTER) end it { @abilities.allowed?(@u1, :read_project, @p1).should be_false } @@ -21,7 +21,7 @@ describe Project do describe "write access" do before do - @p1.users_projects.create(:project => @p1, :user => @u2, :project_access => UsersProject::DEVELOPER) + @p1.users_projects.create(project: @p1, user: @u2, project_access: UsersProject::DEVELOPER) end it { @abilities.allowed?(@u1, :write_project, @p1).should be_false } @@ -30,8 +30,8 @@ describe Project do describe "admin access" do before do - @p1.users_projects.create(:project => @p1, :user => @u1, :project_access => UsersProject::DEVELOPER) - @p1.users_projects.create(:project => @p1, :user => @u2, :project_access => UsersProject::MASTER) + @p1.users_projects.create(project: @p1, user: @u1, project_access: UsersProject::DEVELOPER) + @p1.users_projects.create(project: @p1, user: @u2, project_access: UsersProject::MASTER) end it { @abilities.allowed?(@u1, :admin_project, @p1).should be_false } diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 381fe7592c9..af193295ee3 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -11,7 +11,7 @@ describe Project do it { should have_many(:issues).dependent(:destroy) } it { should have_many(:notes).dependent(:destroy) } it { should have_many(:snippets).dependent(:destroy) } - it { should have_many(:web_hooks).dependent(:destroy) } + it { should have_many(:hooks).dependent(:destroy) } it { should have_many(:deploy_keys).dependent(:destroy) } end @@ -22,21 +22,55 @@ describe Project do end describe "Respond to" do - it { should respond_to(:repository_writers) } - it { should respond_to(:add_access) } - it { should respond_to(:reset_access) } - it { should respond_to(:update_repository) } - it { should respond_to(:destroy_repository) } it { should respond_to(:public?) } it { should respond_to(:private?) } it { should respond_to(:url_to_repo) } it { should respond_to(:path_to_repo) } it { should respond_to(:valid_repo?) } it { should respond_to(:repo_exists?) } + + # Repository Role + it { should respond_to(:tree) } + it { should respond_to(:root_ref) } it { should respond_to(:repo) } it { should respond_to(:tags) } it { should respond_to(:commit) } + it { should respond_to(:commits) } + it { should respond_to(:commits_between) } + it { should respond_to(:commits_with_refs) } + it { should respond_to(:commits_since) } it { should respond_to(:commits_between) } + it { should respond_to(:satellite) } + it { should respond_to(:update_repository) } + it { should respond_to(:destroy_repository) } + it { should respond_to(:archive_repo) } + + # Authority Role + it { should respond_to(:add_access) } + it { should respond_to(:reset_access) } + it { should respond_to(:repository_writers) } + it { should respond_to(:repository_masters) } + it { should respond_to(:repository_readers) } + it { should respond_to(:allow_read_for?) } + it { should respond_to(:guest_access_for?) } + it { should respond_to(:report_access_for?) } + it { should respond_to(:dev_access_for?) } + it { should respond_to(:master_access_for?) } + + # Team Role + it { should respond_to(:team_member_by_name_or_email) } + it { should respond_to(:team_member_by_id) } + it { should respond_to(:add_user_to_team) } + it { should respond_to(:add_users_to_team) } + it { should respond_to(:add_user_id_to_team) } + it { should respond_to(:add_users_ids_to_team) } + + # Project Push Role + it { should respond_to(:observe_push) } + it { should respond_to(:update_merge_requests) } + it { should respond_to(:execute_hooks) } + it { should respond_to(:post_receive_data) } + it { should respond_to(:trigger_post_receive) } end it "should not allow 'gitolite-admin' as repo name" do @@ -45,17 +79,17 @@ describe Project do end it "should return valid url to repo" do - project = Project.new(:path => "somewhere") + project = Project.new(path: "somewhere") project.url_to_repo.should == Gitlab.config.ssh_path + "somewhere.git" end it "should return path to repo" do - project = Project.new(:path => "somewhere") + project = Project.new(path: "somewhere") project.path_to_repo.should == File.join(Rails.root, "tmp", "tests", "somewhere") end it "returns the full web URL for this repo" do - project = Project.new(:code => "somewhere") + project = Project.new(code: "somewhere") project.web_url.should == "#{Gitlab.config.url}/somewhere" end @@ -66,7 +100,7 @@ describe Project do end it "should be invalid repo" do - project = Project.new(:name => "ok_name", :path => "/INVALID_PATH/", :code => "NEOK") + project = Project.new(name: "ok_name", path: "/INVALID_PATH/", code: "NEOK") project.valid_repo?.should be_false end end @@ -86,7 +120,7 @@ describe Project do let(:project) { Factory :project } it 'returns the creation date of the project\'s last event if present' do - last_event = double(:created_at => 'now') + last_event = double(created_at: 'now') project.stub(:events).and_return( [double, double, last_event] ) project.last_activity_date.should == last_event.created_at end @@ -126,7 +160,7 @@ describe Project do end it "should return nil" do - lambda { Project.new(:path => "invalid").repo }.should raise_error(Grit::NoSuchPathError) + lambda { Project.new(path: "invalid").repo }.should raise_error(Grit::NoSuchPathError) end it "should return nil" do @@ -179,10 +213,10 @@ describe Project do before do @merge_request = Factory :merge_request, - :project => project, - :merged => false, - :closed => false - @key = Factory :key, :user_id => project.owner.id + project: project, + merged: false, + closed: false + @key = Factory :key, user_id: project.owner.id end it "should close merge request if last commit from source branch was pushed to target branch" do diff --git a/spec/models/protected_branch_spec.rb b/spec/models/protected_branch_spec.rb index becc1be4d76..1654e3b6f56 100644 --- a/spec/models/protected_branch_spec.rb +++ b/spec/models/protected_branch_spec.rb @@ -24,7 +24,7 @@ describe ProtectedBranch do end describe 'Callbacks' do - subject { ProtectedBranch.new(:project => project, :name => 'branch_name') } + subject { ProtectedBranch.new(project: project, name: 'branch_name') } it 'call update_repository after save' do subject.should_receive(:update_repository) @@ -37,21 +37,8 @@ describe ProtectedBranch do end end - describe '#update_repository' do - let(:gitolite) { mock } - - subject { ProtectedBranch.new(:project => project) } - - it "updates the branch's project repo permissions" do - Gitlab::GitHost.should_receive(:system).and_return(gitolite) - gitolite.should_receive(:update_project).with(project.path, project) - - subject.update_repository - end - end - describe '#commit' do - subject { ProtectedBranch.new(:project => project, :name => 'cant_touch_this') } + subject { ProtectedBranch.new(project: project, name: 'cant_touch_this') } it 'commits itself to its project' do project.should_receive(:commit).with('cant_touch_this') diff --git a/spec/models/system_hook_spec.rb b/spec/models/system_hook_spec.rb new file mode 100644 index 00000000000..56d76ed08cf --- /dev/null +++ b/spec/models/system_hook_spec.rb @@ -0,0 +1,63 @@ +require "spec_helper" + +describe SystemHook do + describe "execute" do + before(:each) { ActiveRecord::Base.observers.enable(:all) } + + before(:each) do + @system_hook = Factory :system_hook + WebMock.stub_request(:post, @system_hook.url) + end + + it "project_create hook" do + user = Factory :user + with_resque do + project = Factory :project_without_owner, owner: user + end + WebMock.should have_requested(:post, @system_hook.url).with(body: /project_create/).once + end + + it "project_destroy hook" do + project = Factory :project + with_resque do + project.destroy + end + WebMock.should have_requested(:post, @system_hook.url).with(body: /project_destroy/).once + end + + it "user_create hook" do + with_resque do + Factory :user + end + WebMock.should have_requested(:post, @system_hook.url).with(body: /user_create/).once + end + + it "user_destroy hook" do + user = Factory :user + with_resque do + user.destroy + end + WebMock.should have_requested(:post, @system_hook.url).with(body: /user_destroy/).once + end + + it "project_create hook" do + user = Factory :user + project = Factory :project + with_resque do + project.users << user + end + WebMock.should have_requested(:post, @system_hook.url).with(body: /user_add_to_team/).once + end + + it "project_destroy hook" do + user = Factory :user + project = Factory :project + project.users << user + with_resque do + project.users_projects.clear + end + WebMock.should have_requested(:post, @system_hook.url).with(body: /user_remove_from_team/).once + end + end + +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 91771ca903b..265dcef1e77 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -18,24 +18,29 @@ describe User do end it "should return valid identifier" do - user = User.new(:email => "test@mail.com") + user = User.new(email: "test@mail.com") user.identifier.should == "test_mail_com" end + it "should return identifier without + sign" do + user = User.new(email: "test+foo@mail.com") + user.identifier.should == "test_foo_mail_com" + end + it "should execute callback when force_random_password specified" do - user = User.new(:email => "test@mail.com", :force_random_password => true) + user = User.new(email: "test@mail.com", force_random_password: true) user.should_receive(:generate_password) user.save end it "should not generate password by default" do - user = Factory(:user, :password => 'abcdefg', :password_confirmation => 'abcdefg') + user = Factory(:user, password: 'abcdefg', password_confirmation: 'abcdefg') user.password.should == 'abcdefg' end it "should generate password when forcing random password" do Devise.stub(:friendly_token).and_return('123456789') - user = User.create(:email => "test1@mail.com", :force_random_password => true) + user = User.create(email: "test1@mail.com", force_random_password: true) user.password.should == user.password_confirmation user.password.should == '12345678' end @@ -49,8 +54,8 @@ describe User do before do @user = Factory :user @note = Factory :note, - :author => @user, - :project => Factory(:project) + author: @user, + project: Factory(:project) end it "should destroy all notes with user" do diff --git a/spec/models/web_hook_spec.rb b/spec/models/web_hook_spec.rb index 9971bd5819d..885947614d7 100644 --- a/spec/models/web_hook_spec.rb +++ b/spec/models/web_hook_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe WebHook do +describe ProjectHook do describe "Associations" do it { should belong_to :project } end @@ -23,32 +23,32 @@ describe WebHook do describe "execute" do before(:each) do - @webhook = Factory :web_hook + @project_hook = Factory :project_hook @project = Factory :project - @project.web_hooks << [@webhook] + @project.hooks << [@project_hook] @data = { before: 'oldrev', after: 'newrev', ref: 'ref'} - WebMock.stub_request(:post, @webhook.url) + WebMock.stub_request(:post, @project_hook.url) end it "POSTs to the web hook URL" do - @webhook.execute(@data) - WebMock.should have_requested(:post, @webhook.url).once + @project_hook.execute(@data) + WebMock.should have_requested(:post, @project_hook.url).once end it "POSTs the data as JSON" do json = @data.to_json - @webhook.execute(@data) - WebMock.should have_requested(:post, @webhook.url).with(body: json).once + @project_hook.execute(@data) + WebMock.should have_requested(:post, @project_hook.url).with(body: json).once end it "catches exceptions" do WebHook.should_receive(:post).and_raise("Some HTTP Post error") lambda { - @webhook.execute(@data) - }.should_not raise_error + @project_hook.execute(@data) + }.should raise_error end end end diff --git a/spec/models/activity_observer_spec.rb b/spec/observers/activity_observer_spec.rb index aed1b26d306..0db4a9985be 100644 --- a/spec/models/activity_observer_spec.rb +++ b/spec/observers/activity_observer_spec.rb @@ -11,7 +11,7 @@ describe ActivityObserver do describe "Merge Request created" do before do MergeRequest.observers.enable :activity_observer do - @merge_request = Factory :merge_request, :project => project + @merge_request = Factory :merge_request, project: project @event = Event.last end end @@ -24,7 +24,7 @@ describe ActivityObserver do describe "Issue created" do before do Issue.observers.enable :activity_observer do - @issue = Factory :issue, :project => project + @issue = Factory :issue, project: project @event = Event.last end end @@ -36,8 +36,8 @@ describe ActivityObserver do #describe "Issue commented" do #before do - #@issue = Factory :issue, :project => project - #@note = Factory :note, :noteable => @issue, :project => project + #@issue = Factory :issue, project: project + #@note = Factory :note, noteable: @issue, project: project #@event = Event.last #end diff --git a/spec/models/issue_observer_spec.rb b/spec/observers/issue_observer_spec.rb index 2b9798f7e53..c6a405f1c1b 100644 --- a/spec/models/issue_observer_spec.rb +++ b/spec/observers/issue_observer_spec.rb @@ -1,9 +1,9 @@ require 'spec_helper' describe IssueObserver do - let(:some_user) { double(:user, :id => 1) } - let(:assignee) { double(:user, :id => 2) } - let(:issue) { double(:issue, :id => 42, :assignee => assignee) } + let(:some_user) { double(:user, id: 1) } + let(:assignee) { double(:user, id: 2) } + let(:issue) { double(:issue, id: 42, assignee: assignee) } before(:each) { subject.stub(:current_user).and_return(some_user) } @@ -15,13 +15,13 @@ describe IssueObserver do subject.should_receive(:after_create) Issue.observers.enable :issue_observer do - Factory.create(:issue, :project => Factory.create(:project)) + Factory.create(:issue, project: Factory.create(:project)) end end it 'sends an email to the assignee' do Notify.should_receive(:new_issue_email).with(issue.id). - and_return(double(:deliver => true)) + and_return(double(deliver: true)) subject.after_create(issue) end @@ -42,7 +42,7 @@ describe IssueObserver do end it 'is called when an issue is changed' do - changed = Factory.create(:issue, :project => Factory.create(:project)) + changed = Factory.create(:issue, project: Factory.create(:project)) subject.should_receive(:after_update) Issue.observers.enable :issue_observer do @@ -101,7 +101,7 @@ describe IssueObserver do end describe '#send_reassigned_email' do - let(:previous_assignee) { double(:user, :id => 3) } + let(:previous_assignee) { double(:user, id: 3) } before(:each) do issue.stub(:assignee_id).and_return(assignee.id) @@ -110,7 +110,7 @@ describe IssueObserver do def it_sends_a_reassigned_email_to(recipient) Notify.should_receive(:reassigned_issue_email).with(recipient, issue.id, previous_assignee.id). - and_return(double(:deliver => true)) + and_return(double(deliver: true)) end def it_does_not_send_a_reassigned_email_to(recipient) diff --git a/spec/models/user_observer_spec.rb b/spec/observers/user_observer_spec.rb index 23dac98bb74..23dac98bb74 100644 --- a/spec/models/user_observer_spec.rb +++ b/spec/observers/user_observer_spec.rb diff --git a/spec/requests/admin/admin_hooks_spec.rb b/spec/requests/admin/admin_hooks_spec.rb new file mode 100644 index 00000000000..2f026aabab8 --- /dev/null +++ b/spec/requests/admin/admin_hooks_spec.rb @@ -0,0 +1,53 @@ +require 'spec_helper' + +describe "Admin::Hooks" do + before do + @project = Factory :project, + name: "LeGiT", + code: "LGT" + login_as :admin + + @system_hook = Factory :system_hook + + end + + describe "GET /admin/hooks" do + it "should be ok" do + visit admin_root_path + within ".main_menu" do + click_on "Hooks" + end + current_path.should == admin_hooks_path + end + + it "should have hooks list" do + visit admin_hooks_path + page.should have_content(@system_hook.url) + end + end + + describe "New Hook" do + before do + @url = Faker::Internet.uri("http") + visit admin_hooks_path + fill_in "hook_url", with: @url + expect { click_button "Add System Hook" }.to change(SystemHook, :count).by(1) + end + + it "should open new hook popup" do + page.current_path.should == admin_hooks_path + page.should have_content(@url) + end + end + + describe "Test" do + before do + WebMock.stub_request(:post, @system_hook.url) + visit admin_hooks_path + click_link "Test Hook" + end + + it { page.current_path.should == admin_hooks_path } + end + +end diff --git a/spec/requests/admin/admin_projects_spec.rb b/spec/requests/admin/admin_projects_spec.rb index fb6577de326..0ce66f5f868 100644 --- a/spec/requests/admin/admin_projects_spec.rb +++ b/spec/requests/admin/admin_projects_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe "Admin::Projects" do before do @project = Factory :project, - :name => "LeGiT", - :code => "LGT" + name: "LeGiT", + code: "LGT" login_as :admin end @@ -41,15 +41,15 @@ describe "Admin::Projects" do end it "should have project edit page" do - page.should have_content("Name") - page.should have_content("Code") + page.should have_content("Project name") + page.should have_content("URL") end describe "Update project" do before do - fill_in "project_name", :with => "Big Bang" - fill_in "project_code", :with => "BB1" - click_button "Save" + fill_in "project_name", with: "Big Bang" + fill_in "project_code", with: "BB1" + click_button "Save Project" @project.reload end @@ -76,20 +76,19 @@ describe "Admin::Projects" do end it "should have labels for new project" do - page.should have_content("Name") - page.should have_content("Path") - page.should have_content("Description") + page.should have_content("Project name is") + page.should have_content("Git Clone") + page.should have_content("URL") end end describe "POST /admin/projects" do before do visit new_admin_project_path - fill_in 'Name', :with => 'NewProject' - fill_in 'Code', :with => 'NPR' - fill_in 'Path', :with => 'gitlabhq_1' - fill_in 'Description', :with => 'New Project Description' - expect { click_button "Save" }.to change { Project.count }.by(1) + fill_in 'project_name', with: 'NewProject' + fill_in 'project_code', with: 'NPR' + fill_in 'project_path', with: 'gitlabhq_1' + expect { click_button "Create project" }.to change { Project.count }.by(1) @project = Project.last end @@ -100,7 +99,6 @@ describe "Admin::Projects" do it "should show project" do page.should have_content(@project.name) page.should have_content(@project.path) - page.should have_content(@project.description) end end @@ -111,7 +109,7 @@ describe "Admin::Projects" do end it "should create new user" do - select @new_user.name, :from => "user_ids" + select @new_user.name, from: "user_ids" expect { click_button "Add" }.to change { UsersProject.count }.by(1) page.should have_content @new_user.name current_path.should == admin_project_path(@project) diff --git a/spec/requests/admin/admin_users_spec.rb b/spec/requests/admin/admin_users_spec.rb index ba6831e3d8b..68358bf0a0f 100644 --- a/spec/requests/admin/admin_users_spec.rb +++ b/spec/requests/admin/admin_users_spec.rb @@ -22,10 +22,10 @@ describe "Admin::Users" do before do @password = "123ABC" visit new_admin_user_path - fill_in "user_name", :with => "Big Bang" - fill_in "user_email", :with => "bigbang@mail.com" - fill_in "user_password", :with => @password - fill_in "user_password_confirmation", :with => @password + fill_in "user_name", with: "Big Bang" + fill_in "user_email", with: "bigbang@mail.com" + fill_in "user_password", with: @password + fill_in "user_password_confirmation", with: @password end it "should create new user" do @@ -40,7 +40,7 @@ describe "Admin::Users" do end it "should call send mail" do - Notify.should_receive(:new_user_email).and_return(stub(:deliver => true)) + Notify.should_receive(:new_user_email).and_return(stub(deliver: true)) User.observers.enable :user_observer do click_button "Save" @@ -88,8 +88,8 @@ describe "Admin::Users" do describe "Update user" do before do - fill_in "user_name", :with => "Big Bang" - fill_in "user_email", :with => "bigbang@mail.com" + fill_in "user_name", with: "Big Bang" + fill_in "user_email", with: "bigbang@mail.com" check "user_admin" click_button "Save" end @@ -114,7 +114,7 @@ describe "Admin::Users" do end it "should create new user" do - select @new_project.name, :from => "project_ids" + select @new_project.name, from: "project_ids" expect { click_button "Add" }.to change { UsersProject.count }.by(1) page.should have_content @new_project.name current_path.should == admin_user_path(@user) diff --git a/spec/requests/admin/security_spec.rb b/spec/requests/admin/security_spec.rb index 0b0edb85a37..6306832628b 100644 --- a/spec/requests/admin/security_spec.rb +++ b/spec/requests/admin/security_spec.rb @@ -2,20 +2,26 @@ require 'spec_helper' describe "Admin::Projects" do describe "GET /admin/projects" do - it { admin_projects_path.should be_allowed_for :admin } - it { admin_projects_path.should be_denied_for :user } - it { admin_projects_path.should be_denied_for :visitor } + subject { admin_projects_path } + + it { should be_allowed_for :admin } + it { should be_denied_for :user } + it { should be_denied_for :visitor } end describe "GET /admin/users" do - it { admin_users_path.should be_allowed_for :admin } - it { admin_users_path.should be_denied_for :user } - it { admin_users_path.should be_denied_for :visitor } + subject { admin_users_path } + + it { should be_allowed_for :admin } + it { should be_denied_for :user } + it { should be_denied_for :visitor } end - describe "GET /admin/emails" do - it { admin_emails_path.should be_allowed_for :admin } - it { admin_emails_path.should be_denied_for :user } - it { admin_emails_path.should be_denied_for :visitor } + describe "GET /admin/hooks" do + subject { admin_hooks_path } + + it { should be_allowed_for :admin } + it { should be_denied_for :user } + it { should be_denied_for :visitor } end end diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb new file mode 100644 index 00000000000..c00a056d079 --- /dev/null +++ b/spec/requests/api/issues_spec.rb @@ -0,0 +1,73 @@ +require 'spec_helper' + +describe Gitlab::API do + include ApiHelpers + + let(:user) { Factory :user } + let!(:project) { Factory :project, owner: user } + let!(:issue) { Factory :issue, author: user, assignee: user, project: project } + before { project.add_access(user, :read) } + + describe "GET /issues" do + it "should return authentication error" do + get api("/issues") + response.status.should == 401 + end + + describe "authenticated GET /issues" do + it "should return an array of issues" do + get api("/issues", user) + response.status.should == 200 + json_response.should be_an Array + json_response.first['title'].should == issue.title + end + end + end + + describe "GET /projects/:id/issues" do + it "should return project issues" do + get api("/projects/#{project.code}/issues", user) + response.status.should == 200 + json_response.should be_an Array + json_response.first['title'].should == issue.title + end + end + + describe "GET /projects/:id/issues/:issue_id" do + it "should return a project issue by id" do + get api("/projects/#{project.code}/issues/#{issue.id}", user) + response.status.should == 200 + json_response['title'].should == issue.title + end + end + + describe "POST /projects/:id/issues" do + it "should create a new project issue" do + post api("/projects/#{project.code}/issues", user), + title: 'new issue', labels: 'label, label2' + response.status.should == 201 + json_response['title'].should == 'new issue' + json_response['description'].should be_nil + json_response['labels'].should == ['label', 'label2'] + end + end + + describe "PUT /projects/:id/issues/:issue_id" do + it "should update a project issue" do + put api("/projects/#{project.code}/issues/#{issue.id}", user), + title: 'updated title', labels: 'label2', closed: 1 + response.status.should == 200 + json_response['title'].should == 'updated title' + json_response['labels'].should == ['label2'] + json_response['closed'].should be_true + end + end + + describe "DELETE /projects/:id/issues/:issue_id" do + it "should delete a project issue" do + expect { + delete api("/projects/#{project.code}/issues/#{issue.id}", user) + }.to change { Issue.count }.by(-1) + end + end +end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb new file mode 100644 index 00000000000..0cbc12af53b --- /dev/null +++ b/spec/requests/api/projects_spec.rb @@ -0,0 +1,135 @@ +require 'spec_helper' + +describe Gitlab::API do + include ApiHelpers + + let(:user) { Factory :user } + let!(:project) { Factory :project, owner: user } + let!(:snippet) { Factory :snippet, author: user, project: project, title: 'example' } + before { project.add_access(user, :read) } + + describe "GET /projects" do + it "should return authentication error" do + get api("/projects") + response.status.should == 401 + end + + describe "authenticated GET /projects" do + it "should return an array of projects" do + get api("/projects", user) + response.status.should == 200 + json_response.should be_an Array + json_response.first['name'].should == project.name + json_response.first['owner']['email'].should == user.email + end + end + end + + describe "GET /projects/:id" do + it "should return a project by id" do + get api("/projects/#{project.id}", user) + response.status.should == 200 + json_response['name'].should == project.name + json_response['owner']['email'].should == user.email + end + + it "should return a project by code name" do + get api("/projects/#{project.code}", user) + response.status.should == 200 + json_response['name'].should == project.name + end + + it "should return a 404 error if not found" do + get api("/projects/42", user) + response.status.should == 404 + json_response['message'].should == '404 Not found' + end + end + + describe "GET /projects/:id/repository/branches" do + it "should return an array of project branches" do + get api("/projects/#{project.code}/repository/branches", user) + response.status.should == 200 + json_response.should be_an Array + json_response.first['name'].should == project.repo.heads.sort_by(&:name).first.name + end + end + + describe "GET /projects/:id/repository/branches/:branch" do + it "should return the branch information for a single branch" do + get api("/projects/#{project.code}/repository/branches/new_design", user) + response.status.should == 200 + + json_response['name'].should == 'new_design' + json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1' + end + end + + describe "GET /projects/:id/repository/tags" do + it "should return an array of project tags" do + get api("/projects/#{project.code}/repository/tags", user) + response.status.should == 200 + json_response.should be_an Array + json_response.first['name'].should == project.repo.tags.sort_by(&:name).reverse.first.name + end + end + + describe "GET /projects/:id/snippets/:snippet_id" do + it "should return a project snippet" do + get api("/projects/#{project.code}/snippets/#{snippet.id}", user) + response.status.should == 200 + json_response['title'].should == snippet.title + end + end + + describe "POST /projects/:id/snippets" do + it "should create a new project snippet" do + post api("/projects/#{project.code}/snippets", user), + title: 'api test', file_name: 'sample.rb', code: 'test' + response.status.should == 201 + json_response['title'].should == 'api test' + end + end + + describe "PUT /projects/:id/snippets" do + it "should update an existing project snippet" do + put api("/projects/#{project.code}/snippets/#{snippet.id}", user), + code: 'updated code' + response.status.should == 200 + json_response['title'].should == 'example' + snippet.reload.content.should == 'updated code' + end + end + + describe "DELETE /projects/:id/snippets/:snippet_id" do + it "should delete existing project snippet" do + expect { + delete api("/projects/#{project.code}/snippets/#{snippet.id}", user) + }.to change { Snippet.count }.by(-1) + end + end + + describe "GET /projects/:id/snippets/:snippet_id/raw" do + it "should get a raw project snippet" do + get api("/projects/#{project.code}/snippets/#{snippet.id}/raw", user) + response.status.should == 200 + end + end + + describe "GET /projects/:id/:sha/blob" do + it "should get the raw file contents" do + get api("/projects/#{project.code}/repository/commits/master/blob?filepath=README.md", user) + response.status.should == 200 + end + + it "should return 404 for invalid branch_name" do + get api("/projects/#{project.code}/repository/commits/invalid_branch_name/blob?filepath=README.md", user) + response.status.should == 404 + end + + it "should return 404 for invalid file" do + get api("/projects/#{project.code}/repository/commits/master/blob?filepath=README.invalid", user) + response.status.should == 404 + end + end +end diff --git a/spec/api/users_spec.rb b/spec/requests/api/users_spec.rb index 32b9379d212..d791962adc2 100644 --- a/spec/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -1,17 +1,19 @@ require 'spec_helper' describe Gitlab::API do + include ApiHelpers + let(:user) { Factory :user } describe "GET /users" do it "should return authentication error" do - get "#{api_prefix}/users" + get api("/users") response.status.should == 401 end describe "authenticated GET /users" do it "should return an array of users" do - get "#{api_prefix}/users?private_token=#{user.private_token}" + get api("/users", user) response.status.should == 200 json_response.should be_an Array json_response.first['email'].should == user.email @@ -21,7 +23,7 @@ describe Gitlab::API do describe "GET /users/:id" do it "should return a user by id" do - get "#{api_prefix}/users/#{user.id}?private_token=#{user.private_token}" + get api("/users/#{user.id}", user) response.status.should == 200 json_response['email'].should == user.email end @@ -29,7 +31,7 @@ describe Gitlab::API do describe "GET /user" do it "should return current user" do - get "#{api_prefix}/user?private_token=#{user.private_token}" + get api("/user", user) response.status.should == 200 json_response['email'].should == user.email end diff --git a/spec/requests/atom/dashboard_issues_spec.rb b/spec/requests/atom/dashboard_issues_spec.rb new file mode 100644 index 00000000000..1d208c70b12 --- /dev/null +++ b/spec/requests/atom/dashboard_issues_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe "User Issues Dashboard" do + describe "GET /issues" do + before do + + login_as :user + + @project1 = Factory :project, + path: "gitlabhq_0", + code: "TEST1" + + @project2 = Factory :project, + path: "gitlabhq_1", + code: "TEST2" + + @project1.add_access(@user, :read, :write) + @project2.add_access(@user, :read, :write) + + @issue1 = Factory :issue, + author: @user, + assignee: @user, + project: @project1 + + @issue2 = Factory :issue, + author: @user, + assignee: @user, + project: @project2 + + visit dashboard_issues_path + end + + describe "atom feed", js: false do + it "should render atom feed via private token" do + logout + visit dashboard_issues_path(:atom, private_token: @user.private_token) + + page.response_headers['Content-Type'].should have_content("application/atom+xml") + page.body.should have_selector("title", text: "#{@user.name} issues") + page.body.should have_selector("author email", text: @issue1.author_email) + page.body.should have_selector("entry summary", text: @issue1.title) + page.body.should have_selector("author email", text: @issue2.author_email) + page.body.should have_selector("entry summary", text: @issue2.title) + end + end + end +end diff --git a/spec/requests/dashboard_spec.rb b/spec/requests/atom/dashboard_spec.rb index 16ededd02af..00c7a5255ca 100644 --- a/spec/requests/dashboard_spec.rb +++ b/spec/requests/atom/dashboard_spec.rb @@ -5,34 +5,22 @@ describe "User Dashboard" do describe "GET /" do before do - @project = Factory :project, :owner => @user + @project = Factory :project, owner: @user @project.add_access(@user, :read) visit dashboard_path end - it "should be on projects page" do - current_path.should == dashboard_path - end - - it "should have link to new project" do - page.should have_content("New Project") - end - - it "should have project" do - page.should have_content(@project.name) - end - it "should render projects atom feed via private token" do logout - visit dashboard_path(:atom, :private_token => @user.private_token) + visit dashboard_path(:atom, private_token: @user.private_token) page.body.should have_selector("feed title") end it "should not render projects page via private token" do logout - visit dashboard_path(:private_token => @user.private_token) + visit dashboard_path(private_token: @user.private_token) current_path.should == new_user_session_path end end diff --git a/spec/requests/atom/issues_spec.rb b/spec/requests/atom/issues_spec.rb new file mode 100644 index 00000000000..468d1b2260a --- /dev/null +++ b/spec/requests/atom/issues_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe "Issues" do + let(:project) { Factory :project } + + before do + login_as :user + project.add_access(@user, :read, :write) + end + + describe "GET /issues" do + before do + @issue = Factory :issue, + author: @user, + assignee: @user, + project: project + + visit project_issues_path(project) + end + + it "should render atom feed" do + visit project_issues_path(project, :atom) + + page.response_headers['Content-Type'].should have_content("application/atom+xml") + page.body.should have_selector("title", text: "#{project.name} issues") + page.body.should have_selector("author email", text: @issue.author_email) + page.body.should have_selector("entry summary", text: @issue.title) + end + + it "should render atom feed via private token" do + logout + visit project_issues_path(project, :atom, private_token: @user.private_token) + + page.response_headers['Content-Type'].should have_content("application/atom+xml") + page.body.should have_selector("title", text: "#{project.name} issues") + page.body.should have_selector("author email", text: @issue.author_email) + page.body.should have_selector("entry summary", text: @issue.title) + end + end +end diff --git a/spec/requests/commits_notes_spec.rb b/spec/requests/commits_notes_spec.rb deleted file mode 100644 index fde42a8f55e..00000000000 --- a/spec/requests/commits_notes_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'spec_helper' - -describe "Issues" do - let(:project) { Factory :project } - let!(:commit) { project.repo.commits.first } - - before do - login_as :user - project.add_access(@user, :read, :write) - end - - describe "add new note", :js => true do - before do - visit project_commit_path(project, commit) - fill_in "note_note", :with => "I commented this commit" - click_button "Add Comment" - end - - it "should conatin new note" do - page.should have_content("I commented this commit") - end - - it "should be displayed when i visit this commit again" do - visit project_commit_path(project, commit) - page.should have_content("I commented this commit") - end - end -end diff --git a/spec/requests/commits_spec.rb b/spec/requests/commits_spec.rb deleted file mode 100644 index 00b69379848..00000000000 --- a/spec/requests/commits_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -require 'spec_helper' - -describe "Commits" do - let(:project) { Factory :project } - let!(:commit) { project.commit } - before do - login_as :user - project.add_access(@user, :read) - end - - describe "GET /commits" do - before do - visit project_commits_path(project) - end - - it "should have valid path" do - current_path.should == project_commits_path(project) - end - - it "should have project name" do - page.should have_content(project.name) - end - - it "should list commits" do - page.should have_content(commit.message) - page.should have_content(commit.id.to_s[0..5]) - end - - it "should render atom feed" do - visit project_commits_path(project, :atom) - - page.response_headers['Content-Type'].should have_content("application/atom+xml") - page.body.should have_selector("title", :text => "Recent commits to #{project.name}") - page.body.should have_selector("author email", :text => commit.author_email) - page.body.should have_selector("entry summary", :text => commit.message) - end - - it "should render atom feed via private token" do - logout - visit project_commits_path(project, :atom, :private_token => @user.private_token) - - page.response_headers['Content-Type'].should have_content("application/atom+xml") - page.body.should have_selector("title", :text => "Recent commits to #{project.name}") - page.body.should have_selector("author email", :text => commit.author_email) - page.body.should have_selector("entry summary", :text => commit.message) - end - end - - describe "GET /commits/:id" do - before do - visit project_commit_path(project, commit.id) - end - - it "should have valid path" do - current_path.should == project_commit_path(project, commit.id) - end - end - - describe "GET /commits/compare" do - before do - visit compare_project_commits_path(project) - end - - it "should have valid path" do - current_path.should == compare_project_commits_path(project) - end - end -end diff --git a/spec/requests/dashboard_issues_spec.rb b/spec/requests/dashboard_issues_spec.rb deleted file mode 100644 index 29c79313f7e..00000000000 --- a/spec/requests/dashboard_issues_spec.rb +++ /dev/null @@ -1,55 +0,0 @@ -require 'spec_helper' - -describe "User Issues Dashboard" do - describe "GET /issues" do - before do - - login_as :user - - @project1 = Factory :project, - :path => "project1", - :code => "TEST1" - - @project2 = Factory :project, - :path => "project2", - :code => "TEST2" - - @project1.add_access(@user, :read, :write) - @project2.add_access(@user, :read, :write) - - @issue1 = Factory :issue, - :author => @user, - :assignee => @user, - :project => @project1 - - @issue2 = Factory :issue, - :author => @user, - :assignee => @user, - :project => @project2 - - visit dashboard_issues_path - end - - subject { page } - - it { should have_content(@issue1.title[0..10]) } - it { should have_content(@issue1.project.name) } - - it { should have_content(@issue2.title[0..10]) } - it { should have_content(@issue2.project.name) } - - describe "atom feed", :js => false do - it "should render atom feed via private token" do - logout - visit dashboard_issues_path(:atom, :private_token => @user.private_token) - - page.response_headers['Content-Type'].should have_content("application/atom+xml") - page.body.should have_selector("title", :text => "#{@user.name} issues") - page.body.should have_selector("author email", :text => @issue1.author_email) - page.body.should have_selector("entry summary", :text => @issue1.title) - page.body.should have_selector("author email", :text => @issue2.author_email) - page.body.should have_selector("entry summary", :text => @issue2.title) - end - end - end -end diff --git a/spec/requests/dashboard_merge_requests_spec.rb b/spec/requests/dashboard_merge_requests_spec.rb deleted file mode 100644 index f345a858ac8..00000000000 --- a/spec/requests/dashboard_merge_requests_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -require 'spec_helper' - -describe "User MergeRequests" do - describe "GET /issues" do - before do - - login_as :user - - @project1 = Factory :project, - :path => "project1", - :code => "TEST1" - - @project2 = Factory :project, - :path => "project2", - :code => "TEST2" - - @project1.add_access(@user, :read, :write) - @project2.add_access(@user, :read, :write) - - @merge_request1 = Factory :merge_request, - :author => @user, - :assignee => @user, - :project => @project1 - - @merge_request2 = Factory :merge_request, - :author => @user, - :assignee => @user, - :project => @project2 - - visit dashboard_merge_requests_path - end - - subject { page } - - it { should have_content(@merge_request1.title[0..10]) } - it { should have_content(@merge_request1.project.name) } - it { should have_content(@merge_request2.title[0..10]) } - it { should have_content(@merge_request2.project.name) } - end -end diff --git a/spec/requests/file_blame_spec.rb b/spec/requests/file_blame_spec.rb deleted file mode 100644 index 511f340c1c8..00000000000 --- a/spec/requests/file_blame_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -require 'spec_helper' - -describe "Blame file" do - before { login_as :user } - - describe "GET /:projectname/:commit/blob/Gemfile" do - before do - @project = Factory :project - @project.add_access(@user, :read) - - visit tree_project_ref_path(@project, @project.root_ref, :path => "Gemfile") - click_link "blame" - end - - it "should be correct path" do - current_path.should == blame_file_project_ref_path(@project, @project.root_ref, :path => "Gemfile") - end - - it "should contain file view" do - page.should have_content("rubygems.org") - page.should have_content("Dmitriy Zaporozhets") - page.should have_content("bc3735004cb Moving to rails 3.2") - end - end -end diff --git a/spec/requests/gitlab_flavored_markdown_spec.rb b/spec/requests/gitlab_flavored_markdown_spec.rb new file mode 100644 index 00000000000..1076e90c42b --- /dev/null +++ b/spec/requests/gitlab_flavored_markdown_spec.rb @@ -0,0 +1,241 @@ +require 'spec_helper' + +describe "Gitlab Flavored Markdown" do + let(:project) { Factory :project } + let(:issue) { Factory :issue, project: project } + let(:merge_request) { Factory :merge_request, project: project } + let(:fred) do + u = Factory :user, name: "fred" + project.users << u + u + end + + before do + # add test branch + @branch_name = "gfm-test" + r = project.repo + i = r.index + # add test file + @test_file = "gfm_test_file" + i.add(@test_file, "foo\nbar\n") + # add commit with gfm + i.commit("fix ##{issue.id}\n\nask @#{fred.name} for details", head: @branch_name) + + # add test tag + @tag_name = "gfm-test-tag" + r.git.native(:tag, {}, @tag_name, commit.id) + end + after do + # delete test branch and tag + project.repo.git.native(:branch, {D: true}, @branch_name) + project.repo.git.native(:tag, {d: true}, @tag_name) + project.repo.gc_auto + end + + let(:commit) { project.commits(@branch_name).first } + + before do + login_as :user + project.add_access(@user, :read, :write) + end + + + describe "for commits" do + it "should render title in commits#index" do + visit project_commits_path(project, ref: @branch_name) + + page.should have_link("##{issue.id}") + end + + it "should render title in commits#show" do + visit project_commit_path(project, id: commit.id) + + page.should have_link("##{issue.id}") + end + + it "should render description in commits#show" do + visit project_commit_path(project, id: commit.id) + + page.should have_link("@#{fred.name}") + end + + it "should render title in refs#tree", js: true do + visit tree_project_ref_path(project, id: @branch_name) + + within(".tree_commit") do + page.should have_link("##{issue.id}") + end + end + + it "should render title in refs#blame" do + visit blame_file_project_ref_path(project, id: @branch_name, path: @test_file) + + within(".blame_commit") do + page.should have_link("##{issue.id}") + end + end + + it "should render title in repositories#branches" do + visit branches_project_repository_path(project) + + page.should have_link("##{issue.id}") + end + + it "should render title in repositories#tags" do + visit tags_project_repository_path(project) + + page.should have_link("##{issue.id}") + end + end + + + describe "for issues" do + before do + @other_issue = Factory :issue, + author: @user, + assignee: @user, + project: project + @issue = Factory :issue, + author: @user, + assignee: @user, + project: project, + title: "fix ##{@other_issue.id}", + description: "ask @#{fred.name} for details" + end + + it "should render subject in issues#index" do + visit project_issues_path(project) + + page.should have_link("##{@other_issue.id}") + end + + it "should render subject in issues#show" do + visit project_issue_path(project, @issue) + + page.should have_link("##{@other_issue.id}") + end + + it "should render details in issues#show" do + visit project_issue_path(project, @issue) + + page.should have_link("@#{fred.name}") + end + end + + + describe "for merge requests" do + before do + @merge_request = Factory :merge_request, + project: project, + title: "fix ##{issue.id}" + end + + it "should render title in merge_requests#index" do + visit project_merge_requests_path(project) + + page.should have_link("##{issue.id}") + end + + it "should render title in merge_requests#show" do + visit project_merge_request_path(project, @merge_request) + + page.should have_link("##{issue.id}") + end + end + + + describe "for milestones" do + before do + @milestone = Factory :milestone, + project: project, + title: "fix ##{issue.id}", + description: "ask @#{fred.name} for details" + end + + it "should render title in milestones#index" do + visit project_milestones_path(project) + + page.should have_link("##{issue.id}") + end + + it "should render title in milestones#show" do + visit project_milestone_path(project, @milestone) + + page.should have_link("##{issue.id}") + end + + it "should render description in milestones#show" do + visit project_milestone_path(project, @milestone) + + page.should have_link("@#{fred.name}") + end + end + + + describe "for notes" do + it "should render in commits#show", js: true do + visit project_commit_path(project, id: commit.id) + fill_in "note_note", with: "see ##{issue.id}" + click_button "Add Comment" + + page.should have_link("##{issue.id}") + end + + it "should render in issue#show", js: true do + visit project_issue_path(project, issue) + fill_in "note_note", with: "see ##{issue.id}" + click_button "Add Comment" + + page.should have_link("##{issue.id}") + end + + it "should render in merge_request#show", js: true do + visit project_merge_request_path(project, merge_request) + fill_in "note_note", with: "see ##{issue.id}" + click_button "Add Comment" + + page.should have_link("##{issue.id}") + end + + it "should render in projects#wall", js: true do + visit wall_project_path(project) + fill_in "note_note", with: "see ##{issue.id}" + click_button "Add Comment" + + page.should have_link("##{issue.id}") + end + + it "should render in wikis#index", js: true do + visit project_wiki_path(project, :index) + fill_in "Title", with: 'Test title' + fill_in "Content", with: '[link test](test)' + click_on "Save" + + fill_in "note_note", with: "see ##{issue.id}" + click_button "Add Comment" + + page.should have_link("##{issue.id}") + end + end + + + describe "for wikis" do + before do + visit project_wiki_path(project, :index) + fill_in "Title", with: "Circumvent ##{issue.id}" + fill_in "Content", with: "# Other pages\n\n* [Foo](foo)\n* [Bar](bar)\n\nAlso look at ##{issue.id} :-)" + click_on "Save" + end + + it "should NOT render title in wikis#show" do + within(".content h3") do # page title + page.should have_content("Circumvent ##{issue.id}") + page.should_not have_link("##{issue.id}") + end + end + + it "should render content in wikis#show" do + page.should have_link("##{issue.id}") + end + end +end diff --git a/spec/requests/hooks_spec.rb b/spec/requests/hooks_spec.rb index a508e5ea517..7cfe7cfe849 100644 --- a/spec/requests/hooks_spec.rb +++ b/spec/requests/hooks_spec.rb @@ -9,7 +9,7 @@ describe "Hooks" do describe "GET index" do it "should be available" do - @hook = Factory :web_hook, :project => @project + @hook = Factory :project_hook, project: @project visit project_hooks_path(@project) page.should have_content "Hooks" page.should have_content @hook.url @@ -20,8 +20,8 @@ describe "Hooks" do before do @url = Faker::Internet.uri("http") visit project_hooks_path(@project) - fill_in "hook_url", :with => @url - expect { click_button "Add Web Hook" }.to change(WebHook, :count).by(1) + fill_in "hook_url", with: @url + expect { click_button "Add Web Hook" }.to change(ProjectHook, :count).by(1) end it "should open new team member popup" do @@ -32,7 +32,8 @@ describe "Hooks" do describe "Test" do before do - @hook = Factory :web_hook, :project => @project + @hook = Factory :project_hook, project: @project + stub_request(:post, @hook.url) visit project_hooks_path(@project) click_link "Test Hook" end diff --git a/spec/requests/issues_notes_spec.rb b/spec/requests/issues_notes_spec.rb deleted file mode 100644 index 538098e60bd..00000000000 --- a/spec/requests/issues_notes_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -require 'spec_helper' - -describe "Issues" do - let(:project) { Factory :project } - - before do - login_as :user - project.add_access(@user, :read, :write) - - @issue = Factory :issue, - :author => @user, - :assignee => @user, - :project => project - end - - describe "add new note", :js => true do - before do - visit project_issue_path(project, @issue) - fill_in "note_note", :with => "I commented this issue" - click_button "Add Comment" - end - - it "should conatin new note" do - page.should have_content("I commented this issue") - end - end -end diff --git a/spec/requests/issues_spec.rb b/spec/requests/issues_spec.rb index 2c8650a8402..15ee5d174a0 100644 --- a/spec/requests/issues_spec.rb +++ b/spec/requests/issues_spec.rb @@ -11,167 +11,12 @@ describe "Issues" do project.add_access(@user2, :read, :write) end - describe "GET /issues" do + describe "Edit issue", js: true do before do @issue = Factory :issue, - :author => @user, - :assignee => @user, - :project => project - - visit project_issues_path(project) - end - - subject { page } - - it { should have_content(@issue.title[0..20]) } - it { should have_content(@issue.project.name) } - it { should have_content(@issue.assignee.name) } - - it "should render atom feed" do - visit project_issues_path(project, :atom) - - page.response_headers['Content-Type'].should have_content("application/atom+xml") - page.body.should have_selector("title", :text => "#{project.name} issues") - page.body.should have_selector("author email", :text => @issue.author_email) - page.body.should have_selector("entry summary", :text => @issue.title) - end - - it "should render atom feed via private token" do - logout - visit project_issues_path(project, :atom, :private_token => @user.private_token) - - page.response_headers['Content-Type'].should have_content("application/atom+xml") - page.body.should have_selector("title", :text => "#{project.name} issues") - page.body.should have_selector("author email", :text => @issue.author_email) - page.body.should have_selector("entry summary", :text => @issue.title) - end - - describe "statuses" do - before do - @closed_issue = Factory :issue, - :author => @user, - :assignee => @user, - :project => project, - :closed => true - end - - it "should show only open" do - should have_content(@issue.title[0..25]) - should have_no_content(@closed_issue.title) - end - - it "should show only closed" do - click_link "Closed" - should have_no_content(@issue.title) - should have_content(@closed_issue.title[0..25]) - end - - it "should show all" do - click_link "All" - should have_content(@issue.title[0..25]) - should have_content(@closed_issue.title[0..25]) - end - end - end - - describe "New issue", :js => true do - before do - visit project_issues_path(project) - click_link "New Issue" - end - - it "should open new issue form" do - page.should have_content("New Issue") - end - - describe "fill in" do - describe 'assign to me' do - before do - fill_in "issue_title", :with => "bug 345" - page.execute_script("$('#issue_assignee_id').show();") - select @user.name, :from => "issue_assignee_id" - end - - it { expect { click_button "Submit new issue" }.to change {Issue.count}.by(1) } - - it "should add new issue to table" do - click_button "Submit new issue" - - page.should_not have_content("Add new issue") - page.should have_content @user.name - page.should have_content "bug 345" - page.should have_content project.name - end - - it "should call send mail" do - Notify.should_not_receive(:new_issue_email) - click_button "Submit new issue" - end - end - - describe 'assign to other' do - before do - fill_in "issue_title", :with => "bug 345" - page.execute_script("$('#issue_assignee_id').show();") - select @user2.name, :from => "issue_assignee_id" - end - - it { expect { click_button "Submit new issue" }.to change {Issue.count}.by(1) } - - it "should add new issue to table" do - click_button "Submit new issue" - - page.should_not have_content("Add new issue") - page.should have_content @user2.name - page.should have_content "bug 345" - page.should have_content project.name - end - - it "should call send mail" do - Issue.observers.enable :issue_observer do - Notify.should_receive(:new_issue_email).and_return(stub(:deliver => true)) - click_button "Submit new issue" - end - end - - it "should send valid email to user" do - Issue.observers.enable :issue_observer do - with_resque do - click_button "Submit new issue" - end - issue = Issue.last - email = ActionMailer::Base.deliveries.last - email.subject.should have_content("New Issue was created") - email.body.should have_content(issue.title) - end - end - - end - end - end - - describe "Show issue" do - before do - @issue = Factory :issue, - :author => @user, - :assignee => @user, - :project => project - - visit project_issue_path(project, @issue) - end - - it "should have valid show page for issue" do - page.should have_content @issue.title - page.should have_content @user.name - end - end - - describe "Edit issue", :js => true do - before do - @issue = Factory :issue, - :author => @user, - :assignee => @user, - :project => project + author: @user, + assignee: @user, + project: project visit project_issues_path(project) click_link "Edit" end @@ -182,8 +27,8 @@ describe "Issues" do describe "fill in" do before do - fill_in "issue_title", :with => "bug 345" - fill_in "issue_description", :with => "bug description" + fill_in "issue_title", with: "bug 345" + fill_in "issue_description", with: "bug description" end it { expect { click_button "Save changes" }.to_not change {Issue.count} } @@ -198,14 +43,14 @@ describe "Issues" do end end - describe "Search issue", :js => true do + describe "Search issue", js: true do before do ['foobar', 'foobar2', 'gitlab'].each do |title| @issue = Factory :issue, - :author => @user, - :assignee => @user, - :project => project, - :title => title + author: @user, + assignee: @user, + project: project, + title: title @issue.save end end @@ -217,7 +62,7 @@ describe "Issues" do visit project_issues_path(project) click_link 'Closed' - fill_in 'issue_search', :with => 'foobar' + fill_in 'issue_search', with: 'foobar' page.should have_content 'foobar' page.should_not have_content 'foobar2' @@ -226,7 +71,7 @@ describe "Issues" do it "should search for term and return the correct results" do visit project_issues_path(project) - fill_in 'issue_search', :with => 'foobar' + fill_in 'issue_search', with: 'foobar' page.should have_content 'foobar' page.should have_content 'foobar2' @@ -235,8 +80,8 @@ describe "Issues" do it "should return all results if term has been cleared" do visit project_issues_path(project) - fill_in "issue_search", :with => "foobar" - # Because fill_in, :with => "" triggers nothing we need to trigger a keyup event + fill_in "issue_search", with: "foobar" + # Because fill_in, with: "" triggers nothing we need to trigger a keyup event page.execute_script("$('.issue_search').val('').keyup();"); page.should have_content 'foobar' @@ -244,4 +89,53 @@ describe "Issues" do page.should have_content 'gitlab' end end + + describe "Filter issue" do + before do + ['foobar', 'barbaz', 'gitlab'].each do |title| + @issue = Factory :issue, + author: @user, + assignee: @user, + project: project, + title: title + end + + @issue = Issue.first + @issue.milestone = Factory(:milestone, project: project) + @issue.assignee = nil + @issue.save + end + + it "should allow filtering by issues with no specified milestone" do + visit project_issues_path(project, milestone_id: '0') + + page.should_not have_content 'foobar' + page.should have_content 'barbaz' + page.should have_content 'gitlab' + end + + it "should allow filtering by a specified milestone" do + visit project_issues_path(project, milestone_id: @issue.milestone.id) + + page.should have_content 'foobar' + page.should_not have_content 'barbaz' + page.should_not have_content 'gitlab' + end + + it "should allow filtering by issues with no specified assignee" do + visit project_issues_path(project, assignee_id: '0') + + page.should have_content 'foobar' + page.should_not have_content 'barbaz' + page.should_not have_content 'gitlab' + end + + it "should allow filtering by a specified assignee" do + visit project_issues_path(project, assignee_id: @user.id) + + page.should_not have_content 'foobar' + page.should have_content 'barbaz' + page.should have_content 'gitlab' + end + end end diff --git a/spec/requests/keys_spec.rb b/spec/requests/keys_spec.rb deleted file mode 100644 index 2bc7c75ba0d..00000000000 --- a/spec/requests/keys_spec.rb +++ /dev/null @@ -1,65 +0,0 @@ -require 'spec_helper' - -describe "Issues" do - before do - login_as :user - end - - describe "GET /keys" do - before do - @key = Factory :key, :user => @user - visit keys_path - end - - subject { page } - - it { should have_content(@key.title) } - - describe "Destroy" do - before { visit key_path(@key) } - - it "should remove entry" do - expect { - click_link "Remove" - }.to change { @user.keys.count }.by(-1) - end - end - end - - describe "New key" do - before do - visit keys_path - click_link "Add new" - end - - it "should open new key popup" do - page.should have_content("New key") - end - - describe "fill in" do - before do - fill_in "key_title", :with => "laptop" - fill_in "key_key", :with => "publickey234=" - end - - it { expect { click_button "Save" }.to change {Key.count}.by(1) } - - it "should add new key to table" do - click_button "Save" - - page.should_not have_content("New key") - page.should have_content "laptop" - end - end - end - - describe "Show page" do - before do - @key = Factory :key, :user => @user - visit key_path(@key) - end - - it { page.should have_content @key.title } - it { page.should have_content @key.key[0..10] } - end -end diff --git a/spec/requests/last_push_widget_spec.rb b/spec/requests/last_push_widget_spec.rb deleted file mode 100644 index 0baa20c6e94..00000000000 --- a/spec/requests/last_push_widget_spec.rb +++ /dev/null @@ -1,52 +0,0 @@ -require 'spec_helper' - -describe "Last Push widget" do - before { login_as :user } - - before do - @project = Factory :project, :owner => @user - @project.add_access(@user, :read) - create_push_event - visit dashboard_path - end - - it "should display last push widget with link to merge request page" do - page.should have_content "Your pushed to branch new_design" - page.should have_link "Create Merge Request" - end - - describe "click create MR" do - before { click_link "Create Merge Request" } - - it { current_path.should == new_project_merge_request_path(@project) } - it { find("#merge_request_source_branch").value.should == "new_design" } - it { find("#merge_request_target_branch").value.should == "master" } - it { find("#merge_request_title").value.should == "New Design" } - end - - - def create_push_event - data = { - :before => "0000000000000000000000000000000000000000", - :after => "0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e", - :ref => "refs/heads/new_design", - :user_id => @user.id, - :user_name => @user.name, - :repository => { - :name => @project.name, - :url => "localhost/rubinius", - :description => "", - :homepage => "localhost/rubinius", - :private => true - } - } - - @event = Event.create( - :project => @project, - :action => Event::Pushed, - :data => data, - :author_id => @user.id - ) - end -end - diff --git a/spec/requests/merge_requests_spec.rb b/spec/requests/merge_requests_spec.rb deleted file mode 100644 index f8b8725f56b..00000000000 --- a/spec/requests/merge_requests_spec.rb +++ /dev/null @@ -1,67 +0,0 @@ -require 'spec_helper' - -describe "MergeRequests" do - let(:project) { Factory :project } - - before do - login_as :user - project.add_access(@user, :read, :write) - @merge_request = Factory :merge_request, - :author => @user, - :assignee => @user, - :project => project - end - - describe "GET /merge_requests" do - before do - visit project_merge_requests_path(project) - end - - subject { page } - - it { should have_content(@merge_request.title[0..10]) } - it { should have_content(@merge_request.target_branch) } - it { should have_content(@merge_request.source_branch) } - it { should have_content(@merge_request.assignee.name) } - end - - describe "GET /merge_request/:id" do - before do - visit project_merge_request_path(project, @merge_request) - end - - subject { page } - - it { should have_content(@merge_request.title[0..10]) } - it { should have_content(@merge_request.target_branch) } - it { should have_content(@merge_request.source_branch) } - it { should have_content(@merge_request.assignee.name) } - - describe "Close merge request" do - before { click_link "Close" } - - it { should have_content(@merge_request.title[0..10]) } - it "Show page should inform user that merge request closed" do - page.should have_content "Closed" - end - end - end - - describe "GET /merge_requests/new" do - before do - visit new_project_merge_request_path(project) - fill_in "merge_request_title", :with => "Merge Request Title" - select "master", :from => "merge_request_source_branch" - select "stable", :from => "merge_request_target_branch" - select @user.name, :from => "merge_request_assignee_id" - click_button "Save" - end - - it { current_path.should == project_merge_request_path(project, project.merge_requests.last) } - - it "should create merge request" do - page.should have_content "Close" - page.should have_content @user.name - end - end -end diff --git a/spec/requests/milestones_spec.rb b/spec/requests/milestones_spec.rb deleted file mode 100644 index f1d5023e6b4..00000000000 --- a/spec/requests/milestones_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -require 'spec_helper' - -describe "Milestones" do - let(:project) { Factory :project } - - before do - login_as :user - project.add_access(@user, :admin) - - @milestone = Factory :milestone, :project => project - @issue = Factory :issue, :project => project - - @milestone.issues << @issue - end - - describe "GET /milestones" do - before do - visit project_milestones_path(project) - end - - subject { page } - - it { should have_content(@milestone.title[0..10]) } - it { should have_content(@milestone.expires_at) } - it { should have_content("Browse Issues") } - end - - describe "GET /milestone/:id" do - before do - visit project_milestone_path(project, @milestone) - end - - subject { page } - - it { should have_content(@milestone.title[0..10]) } - it { should have_content(@milestone.expires_at) } - it { should have_content("Browse Issues") } - end - - describe "GET /milestones/new" do - before do - visit new_project_milestone_path(project) - fill_in "milestone_title", :with => "v2.3" - click_button "Create milestone" - end - - it { current_path.should == project_milestone_path(project, project.milestones.last) } - it { page.should have_content(project.milestones.last.title[0..10]) } - it { page.should have_content(project.milestones.last.expires_at) } - end -end diff --git a/spec/requests/profile_spec.rb b/spec/requests/profile_spec.rb deleted file mode 100644 index 6f9af6085ab..00000000000 --- a/spec/requests/profile_spec.rb +++ /dev/null @@ -1,82 +0,0 @@ -require 'spec_helper' - -describe "Profile" do - before do - login_as :user - end - - describe "Show profile" do - before do - visit profile_path - end - - it { page.should have_content(@user.name) } - end - - describe "Profile update" do - before do - visit profile_path - fill_in "user_skype", :with => "testskype" - fill_in "user_linkedin", :with => "testlinkedin" - fill_in "user_twitter", :with => "testtwitter" - click_button "Save" - @user.reload - end - - it { @user.skype.should == 'testskype' } - it { @user.linkedin.should == 'testlinkedin' } - it { @user.twitter.should == 'testtwitter' } - end - - describe "Reset private token" do - before do - visit profile_token_path - end - - it "should reset private token" do - user_first_token = @user.private_token - click_button "Reset" - @user.reload - @user.private_token.should_not == user_first_token - end - end - - describe "Password update" do - before do - visit profile_password_path - end - - it { page.should have_content("Password") } - it { page.should have_content("Password confirmation") } - - describe "change password" do - before do - @old_pwd = @user.encrypted_password - fill_in "user_password", :with => "777777" - fill_in "user_password_confirmation", :with => "777777" - click_button "Save" - @user.reload - end - - it "should redirect to signin page" do - current_path.should == new_user_session_path - end - - it "should change password" do - @user.encrypted_password.should_not == @old_pwd - end - - describe "login with new password" do - before do - fill_in "user_email", :with => @user.email - fill_in "user_password", :with => "777777" - click_button "Sign in" - end - - it "should login user" do - current_path.should == root_path - end - end - end - end -end diff --git a/spec/requests/projects_deploy_keys_spec.rb b/spec/requests/projects_deploy_keys_spec.rb index 580e55229e1..0fea7b46ce2 100644 --- a/spec/requests/projects_deploy_keys_spec.rb +++ b/spec/requests/projects_deploy_keys_spec.rb @@ -10,7 +10,7 @@ describe "Projects", "DeployKeys" do describe "GET /keys" do before do - @key = Factory :key, :project => project + @key = Factory :key, project: project visit project_deploy_keys_path(project) end @@ -41,8 +41,8 @@ describe "Projects", "DeployKeys" do describe "fill in" do before do - fill_in "key_title", :with => "laptop" - fill_in "key_key", :with => "publickey234=" + fill_in "key_title", with: "laptop" + fill_in "key_key", with: "publickey234=" end it { expect { click_button "Save" }.to change {Key.count}.by(1) } @@ -57,7 +57,7 @@ describe "Projects", "DeployKeys" do describe "Show page" do before do - @key = Factory :key, :project => project + @key = Factory :key, project: project visit project_deploy_key_path(project, @key) end diff --git a/spec/requests/projects_security_spec.rb b/spec/requests/projects_security_spec.rb deleted file mode 100644 index df4d11221c3..00000000000 --- a/spec/requests/projects_security_spec.rb +++ /dev/null @@ -1,187 +0,0 @@ -require 'spec_helper' - -describe "Projects Security" do - describe "GET /" do - it { root_path.should be_allowed_for :admin } - it { root_path.should be_allowed_for :user } - it { root_path.should be_denied_for :visitor } - end - - describe "GET /projects/new" do - it { new_project_path.should be_allowed_for :admin } - it { new_project_path.should be_allowed_for :user } - it { new_project_path.should be_denied_for :visitor } - end - - describe "Project" do - before do - @project = Factory :project - @u1 = Factory :user - @u2 = Factory :user - @u3 = Factory :user - # full access - @project.users_projects.create(:user => @u1, :project_access => UsersProject::MASTER) - # readonly - @project.users_projects.create(:user => @u3, :project_access => UsersProject::REPORTER) - end - - describe "GET /project_code" do - it { project_path(@project).should be_allowed_for @u1 } - it { project_path(@project).should be_allowed_for @u3 } - it { project_path(@project).should be_denied_for :admin } - it { project_path(@project).should be_denied_for @u2 } - it { project_path(@project).should be_denied_for :user } - it { project_path(@project).should be_denied_for :visitor } - end - - describe "GET /project_code/master/tree" do - it { tree_project_ref_path(@project, @project.root_ref).should be_allowed_for @u1 } - it { tree_project_ref_path(@project, @project.root_ref).should be_allowed_for @u3 } - it { tree_project_ref_path(@project, @project.root_ref).should be_denied_for :admin } - it { tree_project_ref_path(@project, @project.root_ref).should be_denied_for @u2 } - it { tree_project_ref_path(@project, @project.root_ref).should be_denied_for :user } - it { tree_project_ref_path(@project, @project.root_ref).should be_denied_for :visitor } - end - - describe "GET /project_code/commits" do - it { project_commits_path(@project).should be_allowed_for @u1 } - it { project_commits_path(@project).should be_allowed_for @u3 } - it { project_commits_path(@project).should be_denied_for :admin } - it { project_commits_path(@project).should be_denied_for @u2 } - it { project_commits_path(@project).should be_denied_for :user } - it { project_commits_path(@project).should be_denied_for :visitor } - end - - describe "GET /project_code/commit" do - it { project_commit_path(@project, @project.commit.id).should be_allowed_for @u1 } - it { project_commit_path(@project, @project.commit.id).should be_allowed_for @u3 } - it { project_commit_path(@project, @project.commit.id).should be_denied_for :admin } - it { project_commit_path(@project, @project.commit.id).should be_denied_for @u2 } - it { project_commit_path(@project, @project.commit.id).should be_denied_for :user } - it { project_commit_path(@project, @project.commit.id).should be_denied_for :visitor } - end - - describe "GET /project_code/team" do - it { team_project_path(@project).should be_allowed_for @u1 } - it { team_project_path(@project).should be_allowed_for @u3 } - it { team_project_path(@project).should be_denied_for :admin } - it { team_project_path(@project).should be_denied_for @u2 } - it { team_project_path(@project).should be_denied_for :user } - it { team_project_path(@project).should be_denied_for :visitor } - end - - describe "GET /project_code/wall" do - it { wall_project_path(@project).should be_allowed_for @u1 } - it { wall_project_path(@project).should be_allowed_for @u3 } - it { wall_project_path(@project).should be_denied_for :admin } - it { wall_project_path(@project).should be_denied_for @u2 } - it { wall_project_path(@project).should be_denied_for :user } - it { wall_project_path(@project).should be_denied_for :visitor } - end - - describe "GET /project_code/blob" do - before do - @commit = @project.commit - @path = @commit.tree.contents.select { |i| i.is_a?(Grit::Blob)}.first.name - @blob_path = blob_project_ref_path(@project, @commit.id, :path => @path) - end - - it { @blob_path.should be_allowed_for @u1 } - it { @blob_path.should be_allowed_for @u3 } - it { @blob_path.should be_denied_for :admin } - it { @blob_path.should be_denied_for @u2 } - it { @blob_path.should be_denied_for :user } - it { @blob_path.should be_denied_for :visitor } - end - - describe "GET /project_code/edit" do - it { edit_project_path(@project).should be_allowed_for @u1 } - it { edit_project_path(@project).should be_denied_for @u3 } - it { edit_project_path(@project).should be_denied_for :admin } - it { edit_project_path(@project).should be_denied_for @u2 } - it { edit_project_path(@project).should be_denied_for :user } - it { edit_project_path(@project).should be_denied_for :visitor } - end - - describe "GET /project_code/deploy_keys" do - it { project_deploy_keys_path(@project).should be_allowed_for @u1 } - it { project_deploy_keys_path(@project).should be_denied_for @u3 } - it { project_deploy_keys_path(@project).should be_denied_for :admin } - it { project_deploy_keys_path(@project).should be_denied_for @u2 } - it { project_deploy_keys_path(@project).should be_denied_for :user } - it { project_deploy_keys_path(@project).should be_denied_for :visitor } - end - - describe "GET /project_code/issues" do - it { project_issues_path(@project).should be_allowed_for @u1 } - it { project_issues_path(@project).should be_allowed_for @u3 } - it { project_issues_path(@project).should be_denied_for :admin } - it { project_issues_path(@project).should be_denied_for @u2 } - it { project_issues_path(@project).should be_denied_for :user } - it { project_issues_path(@project).should be_denied_for :visitor } - end - - describe "GET /project_code/snippets" do - it { project_snippets_path(@project).should be_allowed_for @u1 } - it { project_snippets_path(@project).should be_allowed_for @u3 } - it { project_snippets_path(@project).should be_denied_for :admin } - it { project_snippets_path(@project).should be_denied_for @u2 } - it { project_snippets_path(@project).should be_denied_for :user } - it { project_snippets_path(@project).should be_denied_for :visitor } - end - - describe "GET /project_code/merge_requests" do - it { project_merge_requests_path(@project).should be_allowed_for @u1 } - it { project_merge_requests_path(@project).should be_allowed_for @u3 } - it { project_merge_requests_path(@project).should be_denied_for :admin } - it { project_merge_requests_path(@project).should be_denied_for @u2 } - it { project_merge_requests_path(@project).should be_denied_for :user } - it { project_merge_requests_path(@project).should be_denied_for :visitor } - end - - describe "GET /project_code/repository" do - it { project_repository_path(@project).should be_allowed_for @u1 } - it { project_repository_path(@project).should be_allowed_for @u3 } - it { project_repository_path(@project).should be_denied_for :admin } - it { project_repository_path(@project).should be_denied_for @u2 } - it { project_repository_path(@project).should be_denied_for :user } - it { project_repository_path(@project).should be_denied_for :visitor } - end - - describe "GET /project_code/repository/branches" do - it { branches_project_repository_path(@project).should be_allowed_for @u1 } - it { branches_project_repository_path(@project).should be_allowed_for @u3 } - it { branches_project_repository_path(@project).should be_denied_for :admin } - it { branches_project_repository_path(@project).should be_denied_for @u2 } - it { branches_project_repository_path(@project).should be_denied_for :user } - it { branches_project_repository_path(@project).should be_denied_for :visitor } - end - - describe "GET /project_code/repository/tags" do - it { tags_project_repository_path(@project).should be_allowed_for @u1 } - it { tags_project_repository_path(@project).should be_allowed_for @u3 } - it { tags_project_repository_path(@project).should be_denied_for :admin } - it { tags_project_repository_path(@project).should be_denied_for @u2 } - it { tags_project_repository_path(@project).should be_denied_for :user } - it { tags_project_repository_path(@project).should be_denied_for :visitor } - end - - describe "GET /project_code/hooks" do - it { project_hooks_path(@project).should be_allowed_for @u1 } - it { project_hooks_path(@project).should be_allowed_for @u3 } - it { project_hooks_path(@project).should be_denied_for :admin } - it { project_hooks_path(@project).should be_denied_for @u2 } - it { project_hooks_path(@project).should be_denied_for :user } - it { project_hooks_path(@project).should be_denied_for :visitor } - end - - describe "GET /project_code/files" do - it { files_project_path(@project).should be_allowed_for @u1 } - it { files_project_path(@project).should be_allowed_for @u3 } - it { files_project_path(@project).should be_denied_for :admin } - it { files_project_path(@project).should be_denied_for @u2 } - it { files_project_path(@project).should be_denied_for :user } - it { files_project_path(@project).should be_denied_for :visitor } - end - end -end diff --git a/spec/requests/projects_spec.rb b/spec/requests/projects_spec.rb index c9c348469cc..63f8a696754 100644 --- a/spec/requests/projects_spec.rb +++ b/spec/requests/projects_spec.rb @@ -3,50 +3,9 @@ require 'spec_helper' describe "Projects" do before { login_as :user } - describe "GET /projects/new" do - before do - visit root_path - click_link "New Project" - end - - it "should be correct path" do - current_path.should == new_project_path - end - - it "should have labels for new project" do - page.should have_content("Project name is") - end - end - - describe "POST /projects" do - before do - visit new_project_path - fill_in 'project_name', :with => 'NewProject' - fill_in 'project_code', :with => 'NPR' - fill_in 'project_path', :with => 'newproject' - expect { click_button "Create project" }.to change { Project.count }.by(1) - @project = Project.last - end - - it "should be correct path" do - current_path.should == project_path(@project) - end - - it "should show project" do - page.should have_content(@project.name) - page.should have_content(@project.path) - page.should have_content(@project.description) - end - - it "should init repo instructions" do - page.should have_content("git remote") - page.should have_content(@project.url_to_repo) - end - end - describe "GET /projects/show" do before do - @project = Factory :project, :owner => @user + @project = Factory :project, owner: @user @project.add_access(@user, :read) visit project_path(@project) @@ -57,42 +16,6 @@ describe "Projects" do end end - describe "GET /projects/graph" do - before do - @project = Factory :project - @project.add_access(@user, :read) - - visit graph_project_path(@project) - end - - it "should be correct path" do - current_path.should == graph_project_path(@project) - end - - it "should have as as team member" do - page.should have_content("master") - end - end - - describe "GET /projects/team" do - before do - @project = Factory :project - @project.add_access(@user, :read) - - visit team_project_path(@project, - :path => ValidCommit::BLOB_FILE_PATH, - :commit_id => ValidCommit::ID) - end - - it "should be correct path" do - current_path.should == team_project_path(@project) - end - - it "should have as as team member" do - page.should have_content(@user.name) - end - end - describe "GET /projects/:id/edit" do before do @project = Factory :project @@ -114,13 +37,13 @@ describe "Projects" do describe "PUT /projects/:id" do before do - @project = Factory :project, :owner => @user + @project = Factory :project, owner: @user @project.add_access(@user, :admin, :read) visit edit_project_path(@project) - fill_in 'project_name', :with => 'Awesome' - fill_in 'project_code', :with => 'gitlabhq' + fill_in 'project_name', with: 'Awesome' + fill_in 'project_code', with: 'gitlabhq' click_button "Save" @project = @project.reload end diff --git a/spec/requests/projects_tree_spec.rb b/spec/requests/projects_tree_spec.rb deleted file mode 100644 index acc4f0b9674..00000000000 --- a/spec/requests/projects_tree_spec.rb +++ /dev/null @@ -1,90 +0,0 @@ -require 'spec_helper' - -describe "Projects" do - before { login_as :user } - - describe "GET /projects/tree" do - describe "head" do - before do - @project = Factory :project - @project.add_access(@user, :read) - - visit tree_project_ref_path(@project, @project.root_ref) - end - - it "should be correct path" do - current_path.should == tree_project_ref_path(@project, @project.root_ref) - end - - it_behaves_like :tree_view - end - - describe ValidCommit::ID do - before do - @project = Factory :project - @project.add_access(@user, :read) - - visit tree_project_ref_path(@project, ValidCommit::ID) - end - - it "should be correct path" do - current_path.should == tree_project_ref_path(@project, ValidCommit::ID) - end - - it_behaves_like :tree_view - it_behaves_like :project_side_pane - end - - describe "branch passed" do - before do - @project = Factory :project - @project.add_access(@user, :read) - - visit tree_project_ref_path(@project, @project.root_ref) - end - - it "should be correct path" do - current_path.should == tree_project_ref_path(@project, @project.root_ref) - end - - it_behaves_like :tree_view - it_behaves_like :project_side_pane - end - - # TREE FILE PREVIEW - describe "file preview" do - before do - @project = Factory :project - @project.add_access(@user, :read) - - visit tree_project_ref_path(@project, @project.root_ref, :path => "Gemfile") - end - - it "should be correct path" do - current_path.should == tree_project_ref_path(@project, @project.root_ref) - end - - it "should contain file view" do - page.should have_content("rubygems.org") - end - end - end - - # RAW FILE - describe "GET /projects/blob" do - before do - @project = Factory :project - @project.add_access(@user, :read) - - visit blob_project_ref_path(@project, ValidCommit::ID, :path => ValidCommit::BLOB_FILE_PATH) - end - - it "should be correct path" do - current_path.should == blob_project_ref_path(@project, ValidCommit::ID) - end - - it "raw file response" do - page.source.should == ValidCommit::BLOB_FILE - end - end -end diff --git a/spec/requests/projects_wall_spec.rb b/spec/requests/projects_wall_spec.rb deleted file mode 100644 index b2708fd1a57..00000000000 --- a/spec/requests/projects_wall_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -require 'spec_helper' - -describe "Projects", "Wall" do - let(:project) { Factory :project } - - before do - login_as :user - project.add_access(@user, :read, :write) - end - - describe "View notes on wall", :js => true do - before do - Factory :note, :project => project, :note => "Project specs", :author => @user - visit wall_project_path(project) - end - - it { page.should have_content("Project specs") } - it { page.should have_content(@user.name) } - it { page.should have_content("less than a minute ago") } - end - - describe "add new note", :js => true do - before do - visit wall_project_path(project) - fill_in "note_note", :with => "my post on wall" - click_button "Add Comment" - end - - it "should conatin new note" do - page.should have_content("my post on wall") - end - end -end diff --git a/spec/requests/repositories_spec.rb b/spec/requests/repositories_spec.rb deleted file mode 100644 index 1bf4c8d24b7..00000000000 --- a/spec/requests/repositories_spec.rb +++ /dev/null @@ -1,49 +0,0 @@ -require 'spec_helper' - -describe "Repository" do - - before do - @user = Factory :user - @project = Factory :project - @project.add_access(@user, :read, :write) - login_with @user - end - - describe "GET /:project_name/repository" do - before do - visit project_repository_path(@project) - end - - it "should be on projects page" do - current_path.should == project_repository_path(@project) - end - - it "should have link to last commit for activities tab" do - page.should have_content(@project.commit.safe_message[0..20]) - end - end - - describe "GET /:project_name/repository/branches" do - before do - visit branches_project_repository_path(@project) - end - - it "should have link to repo activities" do - page.should have_content("Branches") - page.should have_content("master") - end - end - - # TODO: Add new repo to seeds with tags list - describe "GET /:project_name/repository/tags" do - before do - visit tags_project_repository_path(@project) - end - - it "should have link to repo activities" do - page.should have_content("Tags") - page.should have_content("v1.2.1") - end - end -end - diff --git a/spec/requests/search_spec.rb b/spec/requests/search_spec.rb index 377bc215a04..537c4d0c64c 100644 --- a/spec/requests/search_spec.rb +++ b/spec/requests/search_spec.rb @@ -6,7 +6,7 @@ describe "Search" do @project = Factory :project @project.add_access(@user, :read) visit search_path - fill_in "search", :with => @project.name[0..3] + fill_in "search", with: @project.name[0..3] click_button "Search" end diff --git a/spec/requests/security/profile_access_spec.rb b/spec/requests/security/profile_access_spec.rb new file mode 100644 index 00000000000..9f6fe6a2b50 --- /dev/null +++ b/spec/requests/security/profile_access_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe "Users Security" do + describe "Project" do + before do + @u1 = Factory :user + end + + describe "GET /login" do + it { new_user_session_path.should_not be_404_for :visitor } + end + + describe "GET /keys" do + subject { keys_path } + + it { should be_allowed_for @u1 } + it { should be_allowed_for :admin } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /profile" do + subject { profile_path } + + it { should be_allowed_for @u1 } + it { should be_allowed_for :admin } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /profile/password" do + subject { profile_password_path } + + it { should be_allowed_for @u1 } + it { should be_allowed_for :admin } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + end +end diff --git a/spec/requests/security/project_access_spec.rb b/spec/requests/security/project_access_spec.rb new file mode 100644 index 00000000000..0cdf43bf84e --- /dev/null +++ b/spec/requests/security/project_access_spec.rb @@ -0,0 +1,219 @@ +require 'spec_helper' + +describe "Application access" do + describe "GET /" do + it { root_path.should be_allowed_for :admin } + it { root_path.should be_allowed_for :user } + it { root_path.should be_denied_for :visitor } + end + + describe "GET /projects/new" do + it { new_project_path.should be_allowed_for :admin } + it { new_project_path.should be_allowed_for :user } + it { new_project_path.should be_denied_for :visitor } + end + + describe "Project" do + before do + @project = Factory :project + @u1 = Factory :user + @u2 = Factory :user + @u3 = Factory :user + # full access + @project.users_projects.create(user: @u1, project_access: UsersProject::MASTER) + # readonly + @project.users_projects.create(user: @u3, project_access: UsersProject::REPORTER) + end + + describe "GET /project_code" do + subject { project_path(@project) } + + it { should be_allowed_for @u1 } + it { should be_allowed_for @u3 } + it { should be_denied_for :admin } + it { should be_denied_for @u2 } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /project_code/master/tree" do + subject { tree_project_ref_path(@project, @project.root_ref) } + + it { should be_allowed_for @u1 } + it { should be_allowed_for @u3 } + it { should be_denied_for :admin } + it { should be_denied_for @u2 } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /project_code/commits" do + subject { project_commits_path(@project) } + + it { should be_allowed_for @u1 } + it { should be_allowed_for @u3 } + it { should be_denied_for :admin } + it { should be_denied_for @u2 } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /project_code/commit" do + subject { project_commit_path(@project, @project.commit.id) } + + it { should be_allowed_for @u1 } + it { should be_allowed_for @u3 } + it { should be_denied_for :admin } + it { should be_denied_for @u2 } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /project_code/team" do + subject { team_project_path(@project) } + + it { should be_allowed_for @u1 } + it { should be_allowed_for @u3 } + it { should be_denied_for :admin } + it { should be_denied_for @u2 } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /project_code/wall" do + subject { wall_project_path(@project) } + + it { should be_allowed_for @u1 } + it { should be_allowed_for @u3 } + it { should be_denied_for :admin } + it { should be_denied_for @u2 } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /project_code/blob" do + before do + commit = @project.commit + path = commit.tree.contents.select { |i| i.is_a?(Grit::Blob)}.first.name + @blob_path = blob_project_ref_path(@project, commit.id, path: path) + end + + it { @blob_path.should be_allowed_for @u1 } + it { @blob_path.should be_allowed_for @u3 } + it { @blob_path.should be_denied_for :admin } + it { @blob_path.should be_denied_for @u2 } + it { @blob_path.should be_denied_for :user } + it { @blob_path.should be_denied_for :visitor } + end + + describe "GET /project_code/edit" do + subject { edit_project_path(@project) } + + it { should be_allowed_for @u1 } + it { should be_denied_for @u3 } + it { should be_denied_for :admin } + it { should be_denied_for @u2 } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /project_code/deploy_keys" do + subject { project_deploy_keys_path(@project) } + + it { should be_allowed_for @u1 } + it { should be_denied_for @u3 } + it { should be_denied_for :admin } + it { should be_denied_for @u2 } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /project_code/issues" do + subject { project_issues_path(@project) } + + it { should be_allowed_for @u1 } + it { should be_allowed_for @u3 } + it { should be_denied_for :admin } + it { should be_denied_for @u2 } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /project_code/snippets" do + subject { project_snippets_path(@project) } + + it { should be_allowed_for @u1 } + it { should be_allowed_for @u3 } + it { should be_denied_for :admin } + it { should be_denied_for @u2 } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /project_code/merge_requests" do + subject { project_merge_requests_path(@project) } + + it { should be_allowed_for @u1 } + it { should be_allowed_for @u3 } + it { should be_denied_for :admin } + it { should be_denied_for @u2 } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /project_code/repository" do + subject { project_repository_path(@project) } + + it { should be_allowed_for @u1 } + it { should be_allowed_for @u3 } + it { should be_denied_for :admin } + it { should be_denied_for @u2 } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /project_code/repository/branches" do + subject { branches_project_repository_path(@project) } + + it { should be_allowed_for @u1 } + it { should be_allowed_for @u3 } + it { should be_denied_for :admin } + it { should be_denied_for @u2 } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /project_code/repository/tags" do + subject { tags_project_repository_path(@project) } + + it { should be_allowed_for @u1 } + it { should be_allowed_for @u3 } + it { should be_denied_for :admin } + it { should be_denied_for @u2 } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /project_code/hooks" do + subject { project_hooks_path(@project) } + + it { should be_allowed_for @u1 } + it { should be_allowed_for @u3 } + it { should be_denied_for :admin } + it { should be_denied_for @u2 } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /project_code/files" do + subject { files_project_path(@project) } + + it { should be_allowed_for @u1 } + it { should be_allowed_for @u3 } + it { should be_denied_for :admin } + it { should be_denied_for @u2 } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + end +end diff --git a/spec/requests/snippets_spec.rb b/spec/requests/snippets_spec.rb index 9b9bb0e96c5..6b993660507 100644 --- a/spec/requests/snippets_spec.rb +++ b/spec/requests/snippets_spec.rb @@ -11,8 +11,8 @@ describe "Snippets" do describe "GET /snippets" do before do @snippet = Factory :snippet, - :author => @user, - :project => project + author: @user, + project: project visit project_snippets_path(project) end @@ -50,9 +50,9 @@ describe "Snippets" do describe "fill in" do before do - fill_in "snippet_title", :with => "login function" - fill_in "snippet_file_name", :with => "test.rb" - fill_in "snippet_content", :with => "def login; end" + fill_in "snippet_title", with: "login function" + fill_in "snippet_file_name", with: "test.rb" + fill_in "snippet_content", with: "def login; end" end it { expect { click_button "Save" }.to change {Snippet.count}.by(1) } @@ -69,8 +69,8 @@ describe "Snippets" do describe "Edit snippet" do before do @snippet = Factory :snippet, - :author => @user, - :project => project + author: @user, + project: project visit project_snippet_path(project, @snippet) click_link "Edit" end @@ -81,9 +81,9 @@ describe "Snippets" do describe "fill in" do before do - fill_in "snippet_title", :with => "login function" - fill_in "snippet_file_name", :with => "test.rb" - fill_in "snippet_content", :with => "def login; end" + fill_in "snippet_title", with: "login function" + fill_in "snippet_file_name", with: "test.rb" + fill_in "snippet_content", with: "def login; end" end it { expect { click_button "Save" }.to_not change {Snippet.count} } diff --git a/spec/requests/team_members_spec.rb b/spec/requests/team_members_spec.rb deleted file mode 100644 index 34e34f59bdb..00000000000 --- a/spec/requests/team_members_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -require 'spec_helper' - -describe "TeamMembers" do - before do - login_as :user - @project = Factory :project - @project.add_access(@user, :read, :admin) - end - - describe "Update profile", :js => true do - it "should update user role" do - @project.master_access_for?(@user).should be_true - visit team_project_path(@project) - select "Developer", :from => "team_member_project_access" - @project.master_access_for?(@user).should be_false - @project.dev_access_for?(@user).should be_true - end - end - - describe "View profile" do - it "should be available" do - visit(team_project_path(@project)) - click_link(@user.name) - page.should have_content @user.skype - page.should_not have_content 'Twitter' - end - end - - describe "New Team member" do - before do - @user_1 = Factory :user - visit team_project_path(@project) - click_link "New Team Member" - end - - it "should open new team member popup" do - page.should have_content("New Team member") - end - - describe "fill in" do - before do - within "#new_team_member" do - select @user_1.name, :from => "team_member_user_id" - select "Reporter", :from => "team_member_project_access" - end - end - - it { expect { click_button "Save";sleep(1) }.to change {UsersProject.count}.by(1) } - - it "should add new member to table" do - click_button "Save" - @member = UsersProject.last - - page.should have_content @user_1.name - - @member.reload - @member.project_access.should == UsersProject::REPORTER - end - end - end - - describe "Cancel membership" do - it "should cancel membership" do - visit project_team_member_path(@project, @project.users_projects.last) - expect { click_link "Remove from team" }.to change { UsersProject.count }.by(-1) - end - end -end diff --git a/spec/requests/user_security_spec.rb b/spec/requests/user_security_spec.rb deleted file mode 100644 index b75a1779a8a..00000000000 --- a/spec/requests/user_security_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -require 'spec_helper' - -describe "Users Security" do - describe "Project" do - before do - @u1 = Factory :user - end - - describe "GET /login" do - #it { new_user_session_path.should be_denied_for @u1 } - #it { new_user_session_path.should be_denied_for :admin } - #it { new_user_session_path.should be_denied_for :user } - it { new_user_session_path.should_not be_404_for :visitor } - end - - describe "GET /keys" do - it { keys_path.should be_allowed_for @u1 } - it { keys_path.should be_allowed_for :admin } - it { keys_path.should be_allowed_for :user } - it { keys_path.should be_denied_for :visitor } - end - - describe "GET /profile" do - it { profile_path.should be_allowed_for @u1 } - it { profile_path.should be_allowed_for :admin } - it { profile_path.should be_allowed_for :user } - it { profile_path.should be_denied_for :visitor } - end - - describe "GET /profile/password" do - it { profile_password_path.should be_allowed_for @u1 } - it { profile_password_path.should be_allowed_for :admin } - it { profile_password_path.should be_allowed_for :user } - it { profile_password_path.should be_denied_for :visitor } - end - end -end diff --git a/spec/requests/wikis_spec.rb b/spec/requests/wikis_spec.rb deleted file mode 100644 index fd66b5e4300..00000000000 --- a/spec/requests/wikis_spec.rb +++ /dev/null @@ -1,35 +0,0 @@ -require 'spec_helper' - -describe "Wiki" do - let(:project) { Factory :project } - - before do - login_as :user - project.add_access(@user, :read, :write) - end - - describe "Add pages" do - before do - visit project_wiki_path(project, :index) - end - - it "should see form" do - page.should have_content("Editing page") - end - - it "should see added page" do - fill_in "Title", :with => 'Test title' - fill_in "Content", :with => '[link test](test)' - click_on "Save" - - page.should have_content("Test title") - page.should have_content("link test") - - click_link "link test" - - page.should have_content("Editing page") - end - - end - -end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 65e7e529a5b..9fb0ad7e249 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,5 +1,7 @@ -require 'simplecov' -SimpleCov.start 'rails' +unless ENV['CI'] + require 'simplecov' + SimpleCov.start 'rails' +end # This file is copied to spec/ when you run 'rails generate rspec:install' ENV["RAILS_ENV"] ||= 'test' @@ -7,59 +9,38 @@ require File.expand_path("../../config/environment", __FILE__) require 'rspec/rails' require 'capybara/rails' require 'capybara/rspec' -require 'capybara/dsl' require 'webmock/rspec' require 'factories' -require 'monkeypatch' require 'email_spec' +require 'headless' # Requires supporting ruby files with custom matchers and macros, etc, # in spec/support/ and its subdirectories. Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} +# Use capybara-webkit +Capybara.javascript_driver = :webkit + +WebMock.disable_net_connect!(allow_localhost: true) + RSpec.configure do |config| - # == Mock Framework - # - # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: - # - # config.mock_with :mocha - # config.mock_with :flexmock - # config.mock_with :rr config.mock_with :rspec - config.include LoginMacros - - # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures - config.fixture_path = "#{::Rails.root}/spec/fixtures" + config.include LoginHelpers, type: :request # If you're not using ActiveRecord, or you'd prefer not to run each of your # examples within a transaction, remove the following line or assign false # instead of true. config.use_transactional_fixtures = false - config.before :each, :type => :integration do - DeviseSessionMock.disable + config.before :all do + headless = Headless.new + headless.start end config.before do - if example.metadata[:js] - DatabaseCleaner.strategy = :truncation - Capybara::Selenium::Driver::DEFAULT_OPTIONS[:resynchronize] = true - else - DatabaseCleaner.strategy = :transaction - end - - DatabaseCleaner.start - - WebMock.disable_net_connect!(allow_localhost: true) - ActiveRecord::Base.observers.disable :all - end - - config.after do - DatabaseCleaner.clean + # !!! Observers disabled by default in tests + ActiveRecord::Base.observers.disable(:all) + # ActiveRecord::Base.observers.enable(:all) end - - config.include RSpec::Rails::RequestExampleGroup, :type => :request, :example_group => { - :file_path => /spec\/api/ - } end diff --git a/spec/support/api.rb b/spec/support/api.rb deleted file mode 100644 index d363d8b9a57..00000000000 --- a/spec/support/api.rb +++ /dev/null @@ -1,7 +0,0 @@ -def api_prefix - "/api/#{Gitlab::API::VERSION}" -end - -def json_response - JSON.parse(response.body) -end diff --git a/spec/support/api_helpers.rb b/spec/support/api_helpers.rb new file mode 100644 index 00000000000..7d9011971dd --- /dev/null +++ b/spec/support/api_helpers.rb @@ -0,0 +1,34 @@ +module ApiHelpers + # Public: Prepend a request path with the path to the API + # + # path - Path to append + # user - User object - If provided, automatically appends private_token query + # string for authenticated requests + # + # Examples + # + # >> api('/issues') + # => "/api/v2/issues" + # + # >> api('/issues', User.last) + # => "/api/v2/issues?private_token=..." + # + # >> api('/issues?foo=bar', User.last) + # => "/api/v2/issues?foo=bar&private_token=..." + # + # Returns the relative path to the requested API resource + def api(path, user = nil) + "/api/#{Gitlab::API::VERSION}#{path}" + + + # Normalize query string + (path.index('?') ? '' : '?') + + + # Append private_token if given a User object + (user.respond_to?(:private_token) ? + "&private_token=#{user.private_token}" : "") + end + + def json_response + JSON.parse(response.body) + end +end diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb new file mode 100644 index 00000000000..f1e072aa15f --- /dev/null +++ b/spec/support/db_cleaner.rb @@ -0,0 +1,18 @@ +require 'database_cleaner' + +RSpec.configure do |config| + config.before do + if example.metadata[:js] + DatabaseCleaner.strategy = :truncation + Capybara::Selenium::Driver::DEFAULT_OPTIONS[:resynchronize] = true + else + DatabaseCleaner.strategy = :transaction + end + + DatabaseCleaner.start + end + + config.after do + DatabaseCleaner.clean + end +end diff --git a/spec/support/js_patch.rb b/spec/support/js_patch.rb deleted file mode 100644 index 0d4ab264e85..00000000000 --- a/spec/support/js_patch.rb +++ /dev/null @@ -1,6 +0,0 @@ -module JsPatch - def confirm_js_popup - page.evaluate_script("window.alert = function(msg) { return true; }") - page.evaluate_script("window.confirm = function(msg) { return true; }") - end -end diff --git a/spec/support/login.rb b/spec/support/login.rb deleted file mode 100644 index 026e336df58..00000000000 --- a/spec/support/login.rb +++ /dev/null @@ -1,30 +0,0 @@ -module LoginMacros - def login_as role - @user = User.create(:email => "user#{User.count}@mail.com", - :name => "John Smith", - :password => "123456", - :password_confirmation => "123456", - :skype => 'user_skype') - - if role == :admin - @user.admin = true - @user.save! - end - - visit new_user_session_path - fill_in "user_email", :with => @user.email - fill_in "user_password", :with => "123456" - click_button "Sign in" - end - - def login_with(user) - visit new_user_session_path - fill_in "user_email", :with => user.email - fill_in "user_password", :with => "123456" - click_button "Sign in" - end - - def logout - click_link "Logout" rescue nil - end -end diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb new file mode 100644 index 00000000000..769034e2286 --- /dev/null +++ b/spec/support/login_helpers.rb @@ -0,0 +1,23 @@ +module LoginHelpers + # Internal: Create and log in as a user of the specified role + # + # role - User role (e.g., :admin, :user) + def login_as(role) + @user = Factory(role) + login_with(@user) + end + + # Internal: Login as the specified user + # + # user - User instance to login with + def login_with(user) + visit new_user_session_path + fill_in "user_email", with: user.email + fill_in "user_password", with: "123456" + click_button "Sign in" + end + + def logout + click_link "Logout" rescue nil + end +end diff --git a/spec/monkeypatch.rb b/spec/support/monkeypatch.rb index 6133631c5de..855a31f06de 100644 --- a/spec/monkeypatch.rb +++ b/spec/support/monkeypatch.rb @@ -35,7 +35,7 @@ class UsersProject end class FakeSatellite - def exists? + def exists? true end @@ -44,4 +44,8 @@ class FakeSatellite end end - +class ProtectedBranch + def update_repository + true + end +end diff --git a/spec/support/shared_examples.rb b/spec/support/shared_examples.rb deleted file mode 100644 index 9fd207d0db2..00000000000 --- a/spec/support/shared_examples.rb +++ /dev/null @@ -1,16 +0,0 @@ -shared_examples_for :project_side_pane do - subject { page } - it { should have_content((@project || project).name) } - it { should have_content("Commits") } - it { should have_content("Files") } -end - -shared_examples_for :tree_view do - subject { page } - - it "should have Tree View of project" do - should have_content("app") - should have_content("History") - should have_content("Gemfile") - end -end diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index c70b2f6cebb..6f4bcca2bf2 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -10,7 +10,7 @@ describe PostReceive do context "web hook" do let(:project) { Factory.create(:project) } - let(:key) { Factory.create(:key, :user => project.owner) } + let(:key) { Factory.create(:key, user: project.owner) } let(:key_id) { key.identifier } it "fetches the correct project" do @@ -22,14 +22,14 @@ describe PostReceive do Key.stub(find_by_identifier: nil) project.should_not_receive(:observe_push) - project.should_not_receive(:execute_web_hooks) + project.should_not_receive(:execute_hooks) PostReceive.perform(project.path, 'sha-old', 'sha-new', 'refs/heads/master', key_id).should be_false end it "asks the project to execute web hooks" do Project.stub(find_by_path: project) - project.should_receive(:execute_web_hooks).with('sha-old', 'sha-new', 'refs/heads/master', project.owner) + project.should_receive(:execute_hooks).with('sha-old', 'sha-new', 'refs/heads/master', project.owner) PostReceive.perform(project.path, 'sha-old', 'sha-new', 'refs/heads/master', key_id) end diff --git a/vendor/assets/images/bg_fallback.png b/vendor/assets/images/bg_fallback.png Binary files differnew file mode 100644 index 00000000000..4b2754b8040 --- /dev/null +++ b/vendor/assets/images/bg_fallback.png diff --git a/vendor/assets/images/icon_sprite.png b/vendor/assets/images/icon_sprite.png Binary files differnew file mode 100644 index 00000000000..636c80f2216 --- /dev/null +++ b/vendor/assets/images/icon_sprite.png diff --git a/vendor/assets/images/progress_bar.gif b/vendor/assets/images/progress_bar.gif Binary files differnew file mode 100644 index 00000000000..156fbb53137 --- /dev/null +++ b/vendor/assets/images/progress_bar.gif diff --git a/vendor/assets/images/slider_handles.png b/vendor/assets/images/slider_handles.png Binary files differnew file mode 100644 index 00000000000..b95a46eca97 --- /dev/null +++ b/vendor/assets/images/slider_handles.png diff --git a/vendor/assets/images/ui-icons_222222_256x240.png b/vendor/assets/images/ui-icons_222222_256x240.png Binary files differnew file mode 100644 index 00000000000..b273ff111d2 --- /dev/null +++ b/vendor/assets/images/ui-icons_222222_256x240.png diff --git a/vendor/assets/images/ui-icons_454545_256x240.png b/vendor/assets/images/ui-icons_454545_256x240.png Binary files differnew file mode 100644 index 00000000000..59bd45b907c --- /dev/null +++ b/vendor/assets/images/ui-icons_454545_256x240.png diff --git a/vendor/assets/javascripts/jquery.tagify.js b/vendor/assets/javascripts/jquery.tagify.js deleted file mode 100644 index f22d4c71191..00000000000 --- a/vendor/assets/javascripts/jquery.tagify.js +++ /dev/null @@ -1,143 +0,0 @@ -/* Author: Alicia Liu */ - -(function ($) { - - $.widget("ui.tagify", { - options: { - delimiters: [13, 188], // what user can type to complete a tag in char codes: [enter], [comma] - outputDelimiter: ',', // delimiter for tags in original input field - cssClass: 'tagify-container', // CSS class to style the tagify div and tags, see stylesheet - addTagPrompt: 'add tags' // placeholder text - }, - - _create: function() { - var self = this, - el = self.element, - opts = self.options; - - this.tags = []; - - // hide text field and replace with a div that contains it's own input field for entering tags - this.tagInput = $("<input type='text'>") - .attr( 'placeholder', opts.addTagPrompt ) - .keypress( function(e) { - var $this = $(this), - pressed = e.which; - - for ( i in opts.delimiters ) { - - if (pressed == opts.delimiters[i]) { - self.add( $this.val() ); - e.preventDefault(); - return false; - } - } - }) - // for some reason, in Safari, backspace is only recognized on keyup - .keyup( function(e) { - var $this = $(this), - pressed = e.which; - - // if backspace is hit with no input, remove the last tag - if (pressed == 8) { // backspace - if ( $this.val() == "" ) { - self.remove(); - return false; - } - return; - } - }); - - this.tagDiv = $("<div></div>") - .addClass( opts.cssClass ) - .click( function() { - $(this).children('input').focus(); - }) - .append( this.tagInput ) - .insertAfter( el.hide() ); - - // if the field isn't empty, parse the field for tags, and prepopulate existing tags - var initVal = $.trim( el.val() ); - - if ( initVal ) { - var initTags = initVal.split( opts.outputDelimiter ); - $.each( initTags, function(i, tag) { - self.add( tag ); - }); - } - }, - - _setOption: function( key, value ) { - options.key = value; - }, - - // add a tag, public function - add: function(text) { - var self = this; - text = text || self.tagInput.val(); - if (text) { - var tagIndex = self.tags.length; - - var removeButton = $("<a href='#'>x</a>") - .click( function() { - self.remove( tagIndex ); - return false; - }); - var newTag = $("<span></span>") - .text( text ) - .append( removeButton ); - - self.tagInput.before( newTag ); - self.tags.push( text ); - self.tagInput.val(''); - } - }, - - // remove a tag by index, public function - // if index is blank, remove the last tag - remove: function( tagIndex ) { - var self = this; - if ( tagIndex == null || tagIndex === (self.tags.length - 1) ) { - this.tagDiv.children("span").last().remove(); - self.tags.pop(); - } - if ( typeof(tagIndex) == 'number' ) { - // otherwise just hide this tag, and we don't mess up the index - this.tagDiv.children( "span:eq(" + tagIndex + ")" ).hide(); - // we rely on the serialize function to remove null values - delete( self.tags[tagIndex] ); - } - }, - - // serialize the tags with the given delimiter, and write it back into the tagified field - serialize: function() { - var self = this; - var delim = self.options.outputDelimiter; - var tagsStr = self.tags.join( delim ); - - // our tags might have deleted entries, remove them here - var dupes = new RegExp(delim + delim + '+', 'g'); // regex: /,,+/g - var ends = new RegExp('^' + delim + '|' + delim + '$', 'g'); // regex: /^,|,$/g - var outputStr = tagsStr.replace( dupes, delim ).replace(ends, ''); - - self.element.val(outputStr); - return outputStr; - }, - - inputField: function() { - return this.tagInput; - }, - - containerDiv: function() { - return this.tagDiv; - }, - - // remove the div, and show original input - destroy: function() { - $.Widget.prototype.destroy.apply(this); - this.tagDiv.remove(); - this.element.show(); - } - }); - -})(jQuery);
\ No newline at end of file diff --git a/vendor/assets/javascripts/jquery.ui.selectmenu.js b/vendor/assets/javascripts/jquery.ui.selectmenu.js deleted file mode 100644 index 957fe4d8887..00000000000 --- a/vendor/assets/javascripts/jquery.ui.selectmenu.js +++ /dev/null @@ -1,844 +0,0 @@ - /* - * jQuery UI selectmenu dev version - * - * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI - * https://github.com/fnagel/jquery-ui/wiki/Selectmenu - */ - -(function($) { - -$.widget("ui.selectmenu", { - getter: "value", - version: "1.8", - eventPrefix: "selectmenu", - options: { - transferClasses: true, - typeAhead: "sequential", - style: 'dropdown', - positionOptions: { - my: "left top", - at: "left bottom", - offset: null - }, - width: null, - menuWidth: null, - handleWidth: 26, - maxHeight: null, - icons: null, - format: null, - bgImage: function() {}, - wrapperElement: "<div />" - }, - - _create: function() { - var self = this, o = this.options; - - // set a default id value, generate a new random one if not set by developer - var selectmenuId = this.element.attr( 'id' ) || 'ui-selectmenu-' + Math.random().toString( 16 ).slice( 2, 10 ); - - // quick array of button and menu id's - this.ids = [ selectmenuId + '-button', selectmenuId + '-menu' ]; - - // define safe mouseup for future toggling - this._safemouseup = true; - - // create menu button wrapper - this.newelement = $( '<a />', { - 'class': this.widgetBaseClass + ' ui-widget ui-state-default ui-corner-all', - 'id' : this.ids[ 0 ], - 'role': 'button', - 'href': '#nogo', - 'tabindex': this.element.attr( 'disabled' ) ? 1 : 0, - 'aria-haspopup': true, - 'aria-owns': this.ids[ 1 ] - }); - this.newelementWrap = $( o.wrapperElement ) - .append( this.newelement ) - .insertAfter( this.element ); - - // transfer tabindex - var tabindex = this.element.attr( 'tabindex' ); - if ( tabindex ) { - this.newelement.attr( 'tabindex', tabindex ); - } - - // save reference to select in data for ease in calling methods - this.newelement.data( 'selectelement', this.element ); - - // menu icon - this.selectmenuIcon = $( '<span class="' + this.widgetBaseClass + '-icon ui-icon"></span>' ) - .prependTo( this.newelement ); - - // append status span to button - this.newelement.prepend( '<span class="' + self.widgetBaseClass + '-status" />' ); - - // make associated form label trigger focus - $( 'label[for="' + selectmenuId + '"]' ) - .attr( 'for', this.ids[0] ) - .bind( 'click.selectmenu', function() { - self.newelement[0].focus(); - return false; - }); - - // click toggle for menu visibility - this.newelement - .bind('mousedown.selectmenu', function(event) { - self._toggle(event, true); - // make sure a click won't open/close instantly - if (o.style == "popup") { - self._safemouseup = false; - setTimeout(function() { self._safemouseup = true; }, 300); - } - return false; - }) - .bind('click.selectmenu', function() { - return false; - }) - .bind("keydown.selectmenu", function(event) { - var ret = false; - switch (event.keyCode) { - case $.ui.keyCode.ENTER: - ret = true; - break; - case $.ui.keyCode.SPACE: - self._toggle(event); - break; - case $.ui.keyCode.UP: - if (event.altKey) { - self.open(event); - } else { - self._moveSelection(-1); - } - break; - case $.ui.keyCode.DOWN: - if (event.altKey) { - self.open(event); - } else { - self._moveSelection(1); - } - break; - case $.ui.keyCode.LEFT: - self._moveSelection(-1); - break; - case $.ui.keyCode.RIGHT: - self._moveSelection(1); - break; - case $.ui.keyCode.TAB: - ret = true; - break; - default: - ret = true; - } - return ret; - }) - .bind('keypress.selectmenu', function(event) { - self._typeAhead(event.which, 'mouseup'); - return true; - }) - .bind('mouseover.selectmenu focus.selectmenu', function() { - if (!o.disabled) { - $(this).addClass(self.widgetBaseClass + '-focus ui-state-hover'); - } - }) - .bind('mouseout.selectmenu blur.selectmenu', function() { - if (!o.disabled) { - $(this).removeClass(self.widgetBaseClass + '-focus ui-state-hover'); - } - }); - - // document click closes menu - $(document).bind("mousedown.selectmenu", function(event) { - self.close(event); - }); - - // change event on original selectmenu - this.element - .bind("click.selectmenu", function() { - self._refreshValue(); - }) - // FIXME: newelement can be null under unclear circumstances in IE8 - // TODO not sure if this is still a problem (fnagel 20.03.11) - .bind("focus.selectmenu", function() { - if (self.newelement) { - self.newelement[0].focus(); - } - }); - - // set width when not set via options - if (!o.width) { - o.width = this.element.outerWidth(); - } - // set menu button width - this.newelement.width(o.width); - - // hide original selectmenu element - this.element.hide(); - - // create menu portion, append to body - this.list = $( '<ul />', { - 'class': 'ui-widget ui-widget-content', - 'aria-hidden': true, - 'role': 'listbox', - 'aria-labelledby': this.ids[0], - 'id': this.ids[1] - }); - this.listWrap = $( o.wrapperElement ) - .addClass( self.widgetBaseClass + '-menu' ) - .append( this.list ) - .appendTo( 'body' ); - - // transfer menu click to menu button - this.list - .bind("keydown.selectmenu", function(event) { - var ret = false; - switch (event.keyCode) { - case $.ui.keyCode.UP: - if (event.altKey) { - self.close(event, true); - } else { - self._moveFocus(-1); - } - break; - case $.ui.keyCode.DOWN: - if (event.altKey) { - self.close(event, true); - } else { - self._moveFocus(1); - } - break; - case $.ui.keyCode.LEFT: - self._moveFocus(-1); - break; - case $.ui.keyCode.RIGHT: - self._moveFocus(1); - break; - case $.ui.keyCode.HOME: - self._moveFocus(':first'); - break; - case $.ui.keyCode.PAGE_UP: - self._scrollPage('up'); - break; - case $.ui.keyCode.PAGE_DOWN: - self._scrollPage('down'); - break; - case $.ui.keyCode.END: - self._moveFocus(':last'); - break; - case $.ui.keyCode.ENTER: - case $.ui.keyCode.SPACE: - self.close(event, true); - $(event.target).parents('li:eq(0)').trigger('mouseup'); - break; - case $.ui.keyCode.TAB: - ret = true; - self.close(event, true); - $(event.target).parents('li:eq(0)').trigger('mouseup'); - break; - case $.ui.keyCode.ESCAPE: - self.close(event, true); - break; - default: - ret = true; - } - return ret; - }) - .bind('keypress.selectmenu', function(event) { - self._typeAhead(event.which, 'focus'); - return true; - }) - // this allows for using the scrollbar in an overflowed list - .bind( 'mousedown.selectmenu mouseup.selectmenu', function() { return false; }); - - // needed when window is resized - // TODO seems to be useless, but causes errors (fnagel 01.08.11) - // see: https://github.com/fnagel/jquery-ui/issues/147 - // $(window).bind( "resize.selectmenu", $.proxy( self._refreshPosition, this ) ); - }, - - _init: function() { - var self = this, o = this.options; - - // serialize selectmenu element options - var selectOptionData = []; - this.element - .find('option') - .each(function() { - var opt = $(this); - selectOptionData.push({ - value: opt.attr('value'), - text: self._formatText(opt.text()), - selected: opt.attr('selected'), - disabled: opt.attr('disabled'), - classes: opt.attr('class'), - typeahead: opt.attr('typeahead'), - parentOptGroup: opt.parent('optgroup'), - bgImage: o.bgImage.call(opt) - }); - }); - - // active state class is only used in popup style - var activeClass = (self.options.style == "popup") ? " ui-state-active" : ""; - - // empty list so we can refresh the selectmenu via selectmenu() - this.list.html(""); - - // write li's - if (selectOptionData.length) { - for (var i = 0; i < selectOptionData.length; i++) { - var thisLiAttr = { role : 'presentation' }; - if ( selectOptionData[ i ].disabled ) { - thisLiAttr[ 'class' ] = this.namespace + '-state-disabled'; - } - var thisAAttr = { - html: selectOptionData[i].text, - href : '#nogo', - tabindex : -1, - role : 'option', - 'aria-selected' : false - }; - if ( selectOptionData[ i ].disabled ) { - thisAAttr[ 'aria-disabled' ] = selectOptionData[ i ].disabled; - } - if ( selectOptionData[ i ].typeahead ) { - thisAAttr[ 'typeahead' ] = selectOptionData[ i ].typeahead; - } - var thisA = $('<a/>', thisAAttr); - var thisLi = $('<li/>', thisLiAttr) - .append(thisA) - .data('index', i) - .addClass(selectOptionData[i].classes) - .data('optionClasses', selectOptionData[i].classes || '') - .bind("mouseup.selectmenu", function(event) { - if (self._safemouseup && !self._disabled(event.currentTarget) && !self._disabled($( event.currentTarget ).parents( "ul>li." + self.widgetBaseClass + "-group " )) ) { - var changed = $(this).data('index') != self._selectedIndex(); - self.index($(this).data('index')); - self.select(event); - if (changed) { - self.change(event); - } - self.close(event, true); - } - return false; - }) - .bind("click.selectmenu", function() { - return false; - }) - .bind('mouseover.selectmenu focus.selectmenu', function(e) { - // no hover if diabled - if (!$(e.currentTarget).hasClass(self.namespace + '-state-disabled') && !$(e.currentTarget).parent("ul").parent("li").hasClass(self.namespace + '-state-disabled')) { - self._selectedOptionLi().addClass(activeClass); - self._focusedOptionLi().removeClass(self.widgetBaseClass + '-item-focus ui-state-hover'); - $(this).removeClass('ui-state-active').addClass(self.widgetBaseClass + '-item-focus ui-state-hover'); - } - }) - .bind('mouseout.selectmenu blur.selectmenu', function() { - if ($(this).is(self._selectedOptionLi().selector)) { - $(this).addClass(activeClass); - } - $(this).removeClass(self.widgetBaseClass + '-item-focus ui-state-hover'); - }); - - // optgroup or not... - if ( selectOptionData[i].parentOptGroup.length ) { - var optGroupName = self.widgetBaseClass + '-group-' + this.element.find( 'optgroup' ).index( selectOptionData[i].parentOptGroup ); - if (this.list.find( 'li.' + optGroupName ).length ) { - this.list.find( 'li.' + optGroupName + ':last ul' ).append( thisLi ); - } else { - $(' <li role="presentation" class="' + self.widgetBaseClass + '-group ' + optGroupName + (selectOptionData[i].parentOptGroup.attr("disabled") ? ' ' + this.namespace + '-state-disabled" aria-disabled="true"' : '"' ) + '><span class="' + self.widgetBaseClass + '-group-label">' + selectOptionData[i].parentOptGroup.attr('label') + '</span><ul></ul></li> ') - .appendTo( this.list ) - .find( 'ul' ) - .append( thisLi ); - } - } else { - thisLi.appendTo(this.list); - } - - // append icon if option is specified - if (o.icons) { - for (var j in o.icons) { - if (thisLi.is(o.icons[j].find)) { - thisLi - .data('optionClasses', selectOptionData[i].classes + ' ' + self.widgetBaseClass + '-hasIcon') - .addClass(self.widgetBaseClass + '-hasIcon'); - var iconClass = o.icons[j].icon || ""; - thisLi - .find('a:eq(0)') - .prepend('<span class="' + self.widgetBaseClass + '-item-icon ui-icon ' + iconClass + '"></span>'); - if (selectOptionData[i].bgImage) { - thisLi.find('span').css('background-image', selectOptionData[i].bgImage); - } - } - } - } - } - } else { - $('<li role="presentation"><a href="#nogo" tabindex="-1" role="option"></a></li>').appendTo(this.list); - } - // we need to set and unset the CSS classes for dropdown and popup style - var isDropDown = ( o.style == 'dropdown' ); - this.newelement - .toggleClass( self.widgetBaseClass + '-dropdown', isDropDown ) - .toggleClass( self.widgetBaseClass + '-popup', !isDropDown ); - this.list - .toggleClass( self.widgetBaseClass + '-menu-dropdown ui-corner-bottom', isDropDown ) - .toggleClass( self.widgetBaseClass + '-menu-popup ui-corner-all', !isDropDown ) - // add corners to top and bottom menu items - .find( 'li:first' ) - .toggleClass( 'ui-corner-top', !isDropDown ) - .end().find( 'li:last' ) - .addClass( 'ui-corner-bottom' ); - this.selectmenuIcon - .toggleClass( 'ui-icon-triangle-1-s', isDropDown ) - .toggleClass( 'ui-icon-triangle-2-n-s', !isDropDown ); - - // transfer classes to selectmenu and list - if ( o.transferClasses ) { - var transferClasses = this.element.attr( 'class' ) || ''; - this.newelement.add( this.list ).addClass( transferClasses ); - } - - // set menu width to either menuWidth option value, width option value, or select width - if ( o.style == 'dropdown' ) { - this.list.width( o.menuWidth ? o.menuWidth : o.width ); - } else { - this.list.width( o.menuWidth ? o.menuWidth : o.width - o.handleWidth ); - } - - // reset height to auto - this.list.css( 'height', 'auto' ); - var listH = this.listWrap.height(); - // calculate default max height - if ( o.maxHeight && o.maxHeight < listH ) { - this.list.height( o.maxHeight ); - } else { - var winH = $( window ).height() / 3; - if ( winH < listH ) this.list.height( winH ); - } - - // save reference to actionable li's (not group label li's) - this._optionLis = this.list.find( 'li:not(.' + self.widgetBaseClass + '-group)' ); - - // transfer disabled state - if ( this.element.attr( 'disabled' ) ) { - this.disable(); - } else { - this.enable() - } - - // update value - this.index( this._selectedIndex() ); - - // needed when selectmenu is placed at the very bottom / top of the page - window.setTimeout( function() { - self._refreshPosition(); - }, 200 ); - }, - - destroy: function() { - this.element.removeData( this.widgetName ) - .removeClass( this.widgetBaseClass + '-disabled' + ' ' + this.namespace + '-state-disabled' ) - .removeAttr( 'aria-disabled' ) - .unbind( ".selectmenu" ); - - // TODO unneded as event binding has been disabled - // $( window ).unbind( ".selectmenu" ); - $( document ).unbind( ".selectmenu" ); - - // unbind click on label, reset its for attr - $( 'label[for=' + this.newelement.attr('id') + ']' ) - .attr( 'for', this.element.attr( 'id' ) ) - .unbind( '.selectmenu' ); - - this.newelementWrap.remove(); - this.listWrap.remove(); - - this.element.show(); - - // call widget destroy function - $.Widget.prototype.destroy.apply(this, arguments); - }, - - _typeAhead: function( code, eventType ){ - var self = this, focusFound = false, C = String.fromCharCode(code).toUpperCase(); - c = C.toLowerCase(); - - if ( self.options.typeAhead == 'sequential' ) { - // clear the timeout so we can use _prevChar - window.clearTimeout('ui.selectmenu-' + self.selectmenuId); - - // define our find var - var find = typeof( self._prevChar ) == 'undefined' ? '' : self._prevChar.join( '' ); - - function focusOptSeq( elem, ind, c ){ - focusFound = true; - $( elem ).trigger( eventType ); - typeof( self._prevChar ) == 'undefined' ? self._prevChar = [ c ] : self._prevChar[ self._prevChar.length ] = c; - } - this.list.find( 'li a' ).each( function( i ) { - if ( !focusFound ) { - // allow the typeahead attribute on the option tag for a more specific lookup - var thisText = $( this ).attr( 'typeahead' ) || $(this).text(); - if ( thisText.indexOf( find + C ) === 0 ) { - focusOptSeq( this, i, C ); - } else if (thisText.indexOf(find+c) === 0 ) { - focusOptSeq( this, i, c ); - } - } - }); - // set a 1 second timeout for sequenctial typeahead - // keep this set even if we have no matches so it doesnt typeahead somewhere else - window.setTimeout( function( el ) { - self._prevChar = undefined; - }, 1000, self ); - - } else { - // define self._prevChar if needed - if ( !self._prevChar ) { self._prevChar = [ '' , 0 ]; } - - focusFound = false; - function focusOpt( elem, ind ){ - focusFound = true; - $( elem ).trigger( eventType ); - self._prevChar[ 1 ] = ind; - } - this.list.find( 'li a' ).each(function( i ){ - if (!focusFound){ - var thisText = $(this).text(); - if ( thisText.indexOf( C ) === 0 || thisText.indexOf( c ) === 0 ) { - if (self._prevChar[0] == C){ - if ( self._prevChar[ 1 ] < i ){ focusOpt( this, i ); } - } else{ - focusOpt( this, i ); - } - } - } - }); - this._prevChar[ 0 ] = C; - } - }, - - // returns some usefull information, called by callbacks only - _uiHash: function() { - var index = this.index(); - return { - index: index, - option: $("option", this.element).get(index), - value: this.element[0].value - }; - }, - - open: function(event) { - var self = this, o = this.options; - if ( self.newelement.attr("aria-disabled") != 'true' ) { - self._closeOthers(event); - self.newelement.addClass('ui-state-active'); - - self.listWrap.appendTo( o.appendTo ); - self.list.attr('aria-hidden', false); - - if ( o.style == "dropdown" ) { - self.newelement.removeClass('ui-corner-all').addClass('ui-corner-top'); - } - - self.listWrap.addClass( self.widgetBaseClass + '-open' ); - // positioning needed for IE7 (tested 01.08.11 on MS VPC Image) - // see https://github.com/fnagel/jquery-ui/issues/147 - if ( $.browser.msie && $.browser.version.substr( 0,1 ) == 7 ) { - self._refreshPosition(); - } - var selected = self.list.attr('aria-hidden', false).find('li:not(.' + self.widgetBaseClass + '-group):eq(' + self._selectedIndex() + '):visible a'); - if (selected.length) selected[0].focus(); - // positioning needed for FF, Chrome, IE8, IE7, IE6 (tested 01.08.11 on MS VPC Image) - self._refreshPosition(); - - self._trigger("open", event, self._uiHash()); - } - }, - - close: function(event, retainFocus) { - if ( this.newelement.is('.ui-state-active') ) { - this.newelement - .removeClass('ui-state-active'); - this.listWrap.removeClass(this.widgetBaseClass + '-open'); - this.list.attr('aria-hidden', true); - if ( this.options.style == "dropdown" ) { - this.newelement.removeClass('ui-corner-top').addClass('ui-corner-all'); - } - if ( retainFocus ) { - this.newelement.focus(); - } - this._trigger("close", event, this._uiHash()); - } - }, - - change: function(event) { - this.element.trigger("change"); - this._trigger("change", event, this._uiHash()); - }, - - select: function(event) { - if (this._disabled(event.currentTarget)) { return false; } - this._trigger("select", event, this._uiHash()); - }, - - _closeOthers: function(event) { - $('.' + this.widgetBaseClass + '.ui-state-active').not(this.newelement).each(function() { - $(this).data('selectelement').selectmenu('close', event); - }); - $('.' + this.widgetBaseClass + '.ui-state-hover').trigger('mouseout'); - }, - - _toggle: function(event, retainFocus) { - if ( this.list.parent().is('.' + this.widgetBaseClass + '-open') ) { - this.close(event, retainFocus); - } else { - this.open(event); - } - }, - - _formatText: function(text) { - return (this.options.format ? this.options.format(text) : text); - }, - - _selectedIndex: function() { - return this.element[0].selectedIndex; - }, - - _selectedOptionLi: function() { - return this._optionLis.eq(this._selectedIndex()); - }, - - _focusedOptionLi: function() { - return this.list.find('.' + this.widgetBaseClass + '-item-focus'); - }, - - _moveSelection: function(amt, recIndex) { - // do nothing if disabled - if (!this.options.disabled) { - var currIndex = parseInt(this._selectedOptionLi().data('index') || 0, 10); - var newIndex = currIndex + amt; - // do not loop when using up key - - if (newIndex < 0) { - newIndex = 0; - } - if (newIndex > this._optionLis.size() - 1) { - newIndex = this._optionLis.size() - 1; - } - // Occurs when a full loop has been made - if (newIndex === recIndex) { return false; } - - if (this._optionLis.eq(newIndex).hasClass( this.namespace + '-state-disabled' )) { - // if option at newIndex is disabled, call _moveFocus, incrementing amt by one - (amt > 0) ? ++amt : --amt; - this._moveSelection(amt, newIndex); - } else { - return this._optionLis.eq(newIndex).trigger('mouseup'); - } - } - }, - - _moveFocus: function(amt, recIndex) { - if (!isNaN(amt)) { - var currIndex = parseInt(this._focusedOptionLi().data('index') || 0, 10); - var newIndex = currIndex + amt; - } else { - var newIndex = parseInt(this._optionLis.filter(amt).data('index'), 10); - } - - if (newIndex < 0) { - newIndex = 0; - } - if (newIndex > this._optionLis.size() - 1) { - newIndex = this._optionLis.size() - 1; - } - - //Occurs when a full loop has been made - if (newIndex === recIndex) { return false; } - - var activeID = this.widgetBaseClass + '-item-' + Math.round(Math.random() * 1000); - - this._focusedOptionLi().find('a:eq(0)').attr('id', ''); - - if (this._optionLis.eq(newIndex).hasClass( this.namespace + '-state-disabled' )) { - // if option at newIndex is disabled, call _moveFocus, incrementing amt by one - (amt > 0) ? ++amt : --amt; - this._moveFocus(amt, newIndex); - } else { - this._optionLis.eq(newIndex).find('a:eq(0)').attr('id',activeID).focus(); - } - - this.list.attr('aria-activedescendant', activeID); - }, - - _scrollPage: function(direction) { - var numPerPage = Math.floor(this.list.outerHeight() / this.list.find('li:first').outerHeight()); - numPerPage = (direction == 'up' ? -numPerPage : numPerPage); - this._moveFocus(numPerPage); - }, - - _setOption: function(key, value) { - this.options[key] = value; - // set - if (key == 'disabled') { - this.close(); - this.element - .add(this.newelement) - .add(this.list)[value ? 'addClass' : 'removeClass']( - this.widgetBaseClass + '-disabled' + ' ' + - this.namespace + '-state-disabled') - .attr("aria-disabled", value); - } - }, - - disable: function(index, type){ - // if options is not provided, call the parents disable function - if ( typeof( index ) == 'undefined' ) { - this._setOption( 'disabled', true ); - } else { - if ( type == "optgroup" ) { - this._disableOptgroup(index); - } else { - this._disableOption(index); - } - } - }, - - enable: function(index, type) { - // if options is not provided, call the parents enable function - if ( typeof( index ) == 'undefined' ) { - this._setOption('disabled', false); - } else { - if ( type == "optgroup" ) { - this._enableOptgroup(index); - } else { - this._enableOption(index); - } - } - }, - - _disabled: function(elem) { - return $(elem).hasClass( this.namespace + '-state-disabled' ); - }, - - _disableOption: function(index) { - var optionElem = this._optionLis.eq(index); - if (optionElem) { - optionElem.addClass(this.namespace + '-state-disabled') - .find("a").attr("aria-disabled", true); - this.element.find("option").eq(index).attr("disabled", "disabled"); - } - }, - - _enableOption: function(index) { - var optionElem = this._optionLis.eq(index); - if (optionElem) { - optionElem.removeClass( this.namespace + '-state-disabled' ) - .find("a").attr("aria-disabled", false); - this.element.find("option").eq(index).removeAttr("disabled"); - } - }, - - _disableOptgroup: function(index) { - var optGroupElem = this.list.find( 'li.' + this.widgetBaseClass + '-group-' + index ); - if (optGroupElem) { - optGroupElem.addClass(this.namespace + '-state-disabled') - .attr("aria-disabled", true); - this.element.find("optgroup").eq(index).attr("disabled", "disabled"); - } - }, - - _enableOptgroup: function(index) { - var optGroupElem = this.list.find( 'li.' + this.widgetBaseClass + '-group-' + index ); - if (optGroupElem) { - optGroupElem.removeClass(this.namespace + '-state-disabled') - .attr("aria-disabled", false); - this.element.find("optgroup").eq(index).removeAttr("disabled"); - } - }, - - index: function(newValue) { - if (arguments.length) { - if (!this._disabled($(this._optionLis[newValue]))) { - this.element[0].selectedIndex = newValue; - this._refreshValue(); - } else { - return false; - } - } else { - return this._selectedIndex(); - } - }, - - value: function(newValue) { - if (arguments.length) { - this.element[0].value = newValue; - this._refreshValue(); - } else { - return this.element[0].value; - } - }, - - _refreshValue: function() { - var activeClass = (this.options.style == "popup") ? " ui-state-active" : ""; - var activeID = this.widgetBaseClass + '-item-' + Math.round(Math.random() * 1000); - // deselect previous - this.list - .find('.' + this.widgetBaseClass + '-item-selected') - .removeClass(this.widgetBaseClass + "-item-selected" + activeClass) - .find('a') - .attr('aria-selected', 'false') - .attr('id', ''); - // select new - this._selectedOptionLi() - .addClass(this.widgetBaseClass + "-item-selected" + activeClass) - .find('a') - .attr('aria-selected', 'true') - .attr('id', activeID); - - // toggle any class brought in from option - var currentOptionClasses = (this.newelement.data('optionClasses') ? this.newelement.data('optionClasses') : ""); - var newOptionClasses = (this._selectedOptionLi().data('optionClasses') ? this._selectedOptionLi().data('optionClasses') : ""); - this.newelement - .removeClass(currentOptionClasses) - .data('optionClasses', newOptionClasses) - .addClass( newOptionClasses ) - .find('.' + this.widgetBaseClass + '-status') - .html( - this._selectedOptionLi() - .find('a:eq(0)') - .html() - ); - - this.list.attr('aria-activedescendant', activeID); - }, - - _refreshPosition: function() { - var o = this.options; - - // if its a native pop-up we need to calculate the position of the selected li - if ( o.style == "popup" && !o.positionOptions.offset ) { - var selected = this._selectedOptionLi(); - var _offset = "0 -" + ( selected.outerHeight() + selected.offset().top - this.list.offset().top ); - } - // update zIndex if jQuery UI is able to process - var zIndexElement = this.element.zIndex(); - if ( zIndexElement ) { - this.listWrap.css( 'zIndex', zIndexElement ); - } - this.listWrap.position({ - // set options for position plugin - of: o.positionOptions.of || this.newelement, - my: o.positionOptions.my, - at: o.positionOptions.at, - offset: o.positionOptions.offset || _offset, - collision: o.positionOptions.collision || 'flip' - }); - } -}); - -})(jQuery); diff --git a/vendor/assets/stylesheets/jquery-ui/jquery.tagify.css b/vendor/assets/stylesheets/jquery-ui/jquery.tagify.css deleted file mode 100644 index d6c178f7132..00000000000 --- a/vendor/assets/stylesheets/jquery-ui/jquery.tagify.css +++ /dev/null @@ -1,34 +0,0 @@ -/* Tagify styles -Author: Alicia Liu test -*/ - -.tagify-container { -} - -.tagify-container > span { - display: inline-block; - padding: 8px 11px 8px 11px; - margin: 1px 5px 0px 0px; - border-radius: 4px; - border: 1px solid #d0e1ff; - background-color: #d0e1ff; - color: #0f326d; - font-weight: bold; - font-size: 14px; -} - -.tagify-container > span > a { - padding-left: 5px !important; - color: #83a5e1; - text-decoration: none; - font-weight: bold; -} - -.tagify-container > input { - border: 0 none; - width: 100px !important; -} - -.tagify-container > input:focus { - outline: none; -}
\ No newline at end of file diff --git a/vendor/assets/stylesheets/jquery-ui/jquery.ui.selectmenu.css b/vendor/assets/stylesheets/jquery-ui/jquery.ui.selectmenu.css deleted file mode 100644 index 481adf5a2a8..00000000000 --- a/vendor/assets/stylesheets/jquery-ui/jquery.ui.selectmenu.css +++ /dev/null @@ -1,33 +0,0 @@ -/* Selectmenu -----------------------------------*/ -.ui-selectmenu { background:none; font-size:12px;display: block; display: inline-block; position: relative; height: 2.2em; vertical-align: middle; text-decoration: none; overflow: hidden; zoom: 1; } -.ui-selectmenu-icon { position:absolute; right:6px; margin-top:-8px; top: 50%; } -.ui-selectmenu-menu { padding:0; margin:0; position:absolute; top: 0; display: none; z-index: 1005;} /* z-index: 1005 to make selectmenu work with dialog */ -.ui-selectmenu-menu ul { padding:0; margin:0; list-style:none; position: relative; overflow: auto; overflow-y: auto ; overflow-x: hidden; } -.ui-selectmenu-open { display: block; } -.ui-selectmenu.ui-widget { background:none; } -.ui-selectmenu-menu-popup { margin-top: -1px; } -.ui-selectmenu-menu-dropdown { } -.ui-selectmenu-menu li.ui-state-active { background:#F7FBFC; border:none; padding:1px 0;} -.ui-selectmenu-menu li { padding:0; margin:0; display: block; border-top: 1px dotted transparent; border-bottom: 1px dotted transparent; border-right-width: 0 !important; border-left-width: 0 !important; font-weight: normal !important; } -.ui-selectmenu-menu li a,.ui-selectmenu-status { line-height: 1.4em; display: block; padding: .405em 2.1em .405em 1em; outline:none; text-decoration:none; } -.ui-selectmenu-menu li.ui-state-disabled a, .ui-state-disabled { cursor: default; } -.ui-selectmenu-menu li.ui-selectmenu-hasIcon a, -.ui-selectmenu-hasIcon .ui-selectmenu-status { padding-left: 20px; position: relative; margin-left: 5px; } -.ui-selectmenu-menu li .ui-icon, .ui-selectmenu-status .ui-icon { position: absolute; top: 1em; margin-top: -8px; left: 0; } -.ui-selectmenu-status { line-height: 1.4em; } -.ui-selectmenu-open li.ui-selectmenu-item-focus { background: none repeat scroll 0 0 #FFF6BF; border:1px solid #eaeaea;} -.ui-selectmenu-open li.ui-selectmenu-item-selected { } -.ui-selectmenu-menu li span,.ui-selectmenu-status span { display:block; margin-bottom: .2em; } -.ui-selectmenu-menu li .ui-selectmenu-item-header { font-weight: bold; } -.ui-selectmenu-menu li .ui-selectmenu-item-content { } -.ui-selectmenu-menu li .ui-selectmenu-item-footer { opacity: .8; } -/* for optgroups */ -.ui-selectmenu-menu .ui-selectmenu-group { font-size: 1em; } -.ui-selectmenu-menu .ui-selectmenu-group .ui-selectmenu-group-label { line-height: 1.4em; display:block; padding: .6em .5em 0; font-weight: bold; } -.ui-selectmenu-menu .ui-selectmenu-group ul { margin: 0; padding: 0; } -/* IE6 workaround (dotted transparent borders) */ -* html .ui-selectmenu-menu li { border-color: pink; filter:chroma(color=pink); width:100%; } -* html .ui-selectmenu-menu li a { position: relative } -/* IE7 workaround (opacity disabled) */ -*+html .ui-state-disabled, *+html .ui-state-disabled a { color: silver; } diff --git a/vendor/assets/stylesheets/jquery.ui.aristo.css b/vendor/assets/stylesheets/jquery.ui.aristo.css new file mode 100644 index 00000000000..8cc6e787730 --- /dev/null +++ b/vendor/assets/stylesheets/jquery.ui.aristo.css @@ -0,0 +1,738 @@ +/* + * jQuery UI CSS Framework 1.8.7 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } + + +/* + * jQuery UI CSS Framework 1.8.7 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + * + * To view and modify this theme, visit http://jqueryui.com/themeroller/?ctl=themeroller + */ + + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Arial,sans-serif; font-size: 1.1em; } +.ui-widget .ui-widget { font-size: 1em; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Arial,sans-serif; font-size: 1em; } +.ui-widget-content { border: 1px solid #B6B6B6; background: #ffffff; color: #4F4F4F; } +.ui-widget-content a { color: #4F4F4F; } +.ui-widget-header { border: 1px solid #B6B6B6; color: #4F4F4F; font-weight: bold; } +.ui-widget-header { + background: #ededed url(bg_fallback.png) 0 0 repeat-x; /* Old browsers */ + background: -moz-linear-gradient(top, #ededed 0%, #c4c4c4 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ededed), color-stop(100%,#c4c4c4)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* Opera11.10+ */ + background: -ms-linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* IE10+ */ + background: linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* W3C */ +} +.ui-widget-header a { color: #4F4F4F; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #B6B6B6; font-weight: normal; color: #4F4F4F; } +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { + background: #ededed url(bg_fallback.png) 0 0 repeat-x; /* Old browsers */ + background: -moz-linear-gradient(top, #ededed 0%, #c4c4c4 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ededed), color-stop(100%,#c4c4c4)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* Opera11.10+ */ + background: -ms-linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* IE10+ */ + background: linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* W3C */ + -webkit-box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset; + -moz-box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset; + box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset; +} +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #4F4F4F; text-decoration: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #9D9D9D; font-weight: normal; color: #313131; } +.ui-state-hover a, .ui-state-hover a:hover { color: #313131; text-decoration: none; } +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { + outline: none; + color: #1c4257; border: 1px solid #7096ab; + background: #ededed url(bg_fallback.png) 0 -50px repeat-x; /* Old browsers */ + background: -moz-linear-gradient(top, #b9e0f5 0%, #92bdd6 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b9e0f5), color-stop(100%,#92bdd6)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* Opera11.10+ */ + background: -ms-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* IE10+ */ + background: linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* W3C */ + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #313131; text-decoration: none; } +.ui-widget :active { outline: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight { border: 1px solid #d2dbf4; background: #f4f8fd; color: #0d2054; -moz-border-radius: 0 !important; -webkit-border-radius: 0 !important; border-radius: 0 !important; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } +.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error { border: 1px solid #e2d0d0; background: #fcf0f0; color: #280b0b; -moz-border-radius: 0 !important; -webkit-border-radius: 0 !important; border-radius: 0 !important; } +.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(ui-icons_222222_256x240.png); } +.ui-widget-content .ui-icon {background-image: url(ui-icons_222222_256x240.png); } +.ui-widget-header .ui-icon {background-image: url(ui-icons_222222_256x240.png); } +.ui-state-default .ui-icon { background-image: url(ui-icons_454545_256x240.png); } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(ui-icons_454545_256x240.png); } +.ui-state-active .ui-icon {background-image: url(ui-icons_454545_256x240.png); } +.ui-state-highlight .ui-icon {background-image: url(ui-icons_454545_256x240.png); } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon { background: url(icon_sprite.png) -16px 0 no-repeat !important; } +.ui-state-highlight .ui-icon, .ui-state-error .ui-icon { margin-top: -1px; } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background: url(icon_sprite.png) 0 0 no-repeat !important; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-off { background-position: -96px -144px; } +.ui-icon-radio-on { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-tl { -moz-border-radius-topleft: 3px; -webkit-border-top-left-radius: 3px; border-top-left-radius: 3px; } +.ui-corner-tr { -moz-border-radius-topright: 3px; -webkit-border-top-right-radius: 3px; border-top-right-radius: 3px; } +.ui-corner-bl { -moz-border-radius-bottomleft: 3px; -webkit-border-bottom-left-radius: 3px; border-bottom-left-radius: 3px; } +.ui-corner-br { -moz-border-radius-bottomright: 3px; -webkit-border-bottom-right-radius: 3px; border-bottom-right-radius: 3px; } +.ui-corner-top { -moz-border-radius-topleft: 3px; -webkit-border-top-left-radius: 3px; border-top-left-radius: 3px; -moz-border-radius-topright: 3px; -webkit-border-top-right-radius: 3px; border-top-right-radius: 3px; } +.ui-corner-bottom { -moz-border-radius-bottomleft: 3px; -webkit-border-bottom-left-radius: 3px; border-bottom-left-radius: 3px; -moz-border-radius-bottomright: 3px; -webkit-border-bottom-right-radius: 3px; border-bottom-right-radius: 3px; } +.ui-corner-right { -moz-border-radius-topright: 3px; -webkit-border-top-right-radius: 3px; border-top-right-radius: 3px; -moz-border-radius-bottomright: 3px; -webkit-border-bottom-right-radius: 3px; border-bottom-right-radius: 3px; } +.ui-corner-left { -moz-border-radius-topleft: 3px; -webkit-border-top-left-radius: 3px; border-top-left-radius: 3px; -moz-border-radius-bottomleft: 3px; -webkit-border-bottom-left-radius: 3px; border-bottom-left-radius: 3px; } +.ui-corner-all { -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; } + +/* Overlays */ +.ui-widget-overlay { background: #262b33; opacity: .70;filter:Alpha(Opacity=70); } +.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #000000; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/* + * jQuery UI Resizable 1.8.7 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Resizable#theming + */ +.ui-resizable { position: relative;} +.ui-resizable-handle { position: absolute; font-size: 0.1px; z-index: 999; display: block;} +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* + * jQuery UI Selectable 1.8.7 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Selectable#theming + */ +.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } +/* + * jQuery UI Accordion 1.8.7 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Accordion#theming + */ +/* IE/Win - Fix animation bug - #4615 */ +.ui-accordion { width: 100%; } +.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } +.ui-accordion .ui-accordion-header, .ui-accordion .ui-accordion-content { -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; } +.ui-accordion .ui-accordion-li-fix { display: inline; } +.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } +.ui-accordion .ui-accordion-header a { display: block; font-size: 12px; font-weight: bold; padding: .5em .5em .5em .7em; } +.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } +.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } +.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } +.ui-accordion .ui-accordion-content-active { display: block; }/* + * jQuery UI Autocomplete 1.8.7 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Autocomplete#theming + */ +.ui-autocomplete { + position: absolute; cursor: default; z-index: 3; + -moz-border-radius: 0; + -webkit-border-radius: 0; + border-radius: 0; + -moz-box-shadow: 0 1px 5px rgba(0,0,0,0.3); + -webkit-box-shadow: 0 1px 5px rgba(0,0,0,0.3); + box-shadow: 0 1px 5px rgba(0,0,0,0.3); +} + +/* workarounds */ +* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ + +/* + * jQuery UI Menu 1.8.7 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Menu#theming + */ +.ui-menu { + list-style:none; + padding: 2px; + margin: 0; + display:block; + float: left; +} +.ui-menu .ui-menu { + margin-top: -3px; +} +.ui-menu .ui-menu-item { + margin:0; + padding: 0; + zoom: 1; + float: left; + clear: left; + width: 100%; +} +.ui-menu .ui-menu-item a { + text-decoration:none; + display:block; + padding:.2em .4em; + line-height:1.5; + zoom:1; +} +.ui-menu .ui-menu-item a.ui-state-hover, +.ui-menu .ui-menu-item a.ui-state-active { + font-weight: normal; + margin: -1px; + background: #5f83b9; + color: #FFFFFF; + text-shadow: 0px 1px 1px #234386; + border-color: #466086; + -moz-border-radius: 0; + -webkit-border-radius: 0; + border-radius: 0; +} +/* + * jQuery UI Button 1.8.7 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Button#theming + */ +.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; -webkit-user-select: none; -moz-user-select: none; user-select: none; } /* the overflow property removes extra width in IE */ +.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ +button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ +.ui-button-icons-only { width: 3.4em; } +button.ui-button-icons-only { width: 3.7em; } + +/* button animation properties */ +.ui-button { + -webkit-transition: all 250ms ease-in-out; + -moz-transition: all 250ms ease-in-out; + -o-transition: all 250ms ease-in-out; + transition: all 250ms ease-in-out; +} + +/*states*/ +.ui-button.ui-state-hover { + -moz-box-shadow: 0 0 8px rgba(0, 0, 0, 0.15), 0 1px 0 rgba(255,255,255,0.8) inset; + -webkit-box-shadow: 0 0 8px rgba(0, 0, 0, 0.15), 0 1px 0 rgba(255,255,255,0.8) inset; + box-shadow: 0 0 8px rgba(0, 0, 0, 0.15), 0 1px 0 rgba(255,255,255,0.8) inset; +} +.ui-button.ui-state-focus { + outline: none; + color: #1c4257; + border-color: #7096ab; + background: #ededed url(bg_fallback.png) 0 -50px repeat-x; /* Old browsers */ + background: -moz-linear-gradient(top, #b9e0f5 0%, #92bdd6 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b9e0f5), color-stop(100%,#92bdd6)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* Opera11.10+ */ + background: -ms-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* IE10+ */ + background: linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* W3C */ + -moz-box-shadow: 0 0 8px rgba(0, 0, 0, 0.15), 0 1px 0 rgba(255,255,255,0.8) inset; + -webkit-box-shadow: 0 0 8px rgba(0, 0, 0, 0.15), 0 1px 0 rgba(255,255,255,0.8) inset; + box-shadow: 0 0 8px rgba(0, 0, 0, 0.15), 0 1px 0 rgba(255,255,255,0.8) inset; +} + +/*button text element */ +.ui-button .ui-button-text { display: block; line-height: 1.4; font-size: 14px; font-weight: bold; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6); } +.ui-button-text-only .ui-button-text { padding: .4em 1em; } +.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } +.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } +.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } +.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } +/* no icon support for input elements, provide padding by default */ +input.ui-button, .ui-widget-content input.ui-button { font-size: 14px; font-weight: bold; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6); padding: 0 1em !important; height: 33px; } +/*remove submit button internal padding in Firefox*/ +input.ui-button::-moz-focus-inner { + border: 0; + padding: 0; +} +/* fix webkits handling of the box model */ +@media screen and (-webkit-min-device-pixel-ratio:0) { + input.ui-button { + height: 31px !important; + } +} + + +/*button icon element(s) */ +.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } +.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } +.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } +.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } +.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } + +/*button sets*/ +.ui-buttonset { margin-right: 7px; } +.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } +.ui-buttonset .ui-button.ui-state-active { color: #1c4257; border-color: #7096ab; } +.ui-buttonset .ui-button.ui-state-active { + background: #ededed url(bg_fallback.png) 0 -50px repeat-x; /* Old browsers */ + background: -moz-linear-gradient(top, #b9e0f5 0%, #92bdd6 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b9e0f5), color-stop(100%,#92bdd6)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* Opera11.10+ */ + background: -ms-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* IE10+ */ + background: linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* W3C */ + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +/* workarounds */ +button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ +/* + * jQuery UI Dialog 1.8.7 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Dialog#theming + */ +.ui-dialog { position: absolute; padding: 0; width: 300px; overflow: hidden; } +.ui-dialog { + -webkit-box-shadow: 0 2px 12px rgba(0,0,0,0.6); + -moz-box-shadow: 0 2px 12px rgba(0,0,0,0.6); + box-shadow: 0 2px 12px rgba(0,0,0,0.6); +} +.ui-dialog .ui-dialog-titlebar { padding: 0.7em 1em 0.6em 1em; position: relative; border: none; border-bottom: 1px solid #979797; -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; } +.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 0; font-size: 14px; text-shadow: 0 1px 0 rgba(255,255,255,0.5); } +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .8em; top: 55%; width: 16px; margin: -10px 0 0 0; padding: 0; height: 16px; } +.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; background: url(icon_sprite.png) 0 -16px no-repeat; } +.ui-dialog .ui-dialog-titlebar-close:hover span { background-position: -16px -16px; } +.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; border: 0; } +.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } +.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } +.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } +.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } +.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } +.ui-draggable .ui-dialog-titlebar { cursor: move; } +/* + * jQuery UI Slider 1.8.7 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Slider#theming + */ +.ui-slider { position: relative; text-align: left; background: #d7d7d7; z-index: 1; } +.ui-slider { -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.5) inset; -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.5) inset; box-shadow: 0 1px 2px rgba(0,0,0,0.5) inset; } +.ui-slider .ui-slider-handle { background: url(slider_handles.png) 0px -23px no-repeat; position: absolute; z-index: 2; width: 23px; height: 23px; cursor: default; border: none; outline: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } +.ui-slider .ui-state-hover, .ui-slider .ui-state-active { background-position: 0 0; } +.ui-slider .ui-slider-range { background: #a3cae0; position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } +.ui-slider .ui-slider-range { -moz-box-shadow: 0 1px 2px rgba(17,35,45,0.6) inset; -webkit-box-shadow: 0 1px 2px rgba(17,35,45,0.6) inset; box-shadow: 0 1px 2px rgba(17,35,45,0.6) inset; } + + +.ui-slider-horizontal { height: 5px; } +.ui-slider-horizontal .ui-slider-handle { top: -8px; margin-left: -13px; } +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } +.ui-slider-horizontal .ui-slider-range-min { left: 0; } +.ui-slider-horizontal .ui-slider-range-max { right: 0; } + +.ui-slider-vertical { width: 5px; height: 100px; } +.ui-slider-vertical .ui-slider-handle { left: -8px; margin-left: 0; margin-bottom: -13px; } +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } +.ui-slider-vertical .ui-slider-range-max { top: 0; }/* + * jQuery UI Tabs 1.8.7 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Tabs#theming + */ +.ui-tabs { position: relative; zoom: 1; border: 0; background: transparent; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ +.ui-tabs .ui-tabs-nav { margin: 0; padding: 0; background: transparent; border-width: 0 0 1px 0; } +.ui-tabs .ui-tabs-nav { + -moz-border-radius: 0; + -webkit-border-radius: 0; + border-radius: 0; +} +.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } +.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; font-size: 12px; font-weight: bold; text-shadow: 0 1px 0 rgba(255,255,255,0.5); } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; background: #fff; border-color: #B6B6B6; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; outline: none; } +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs .ui-tabs-panel { display: block; border-width: 0 1px 1px 1px; padding: 1em 1.4em; background: none; } +.ui-tabs .ui-tabs-panel { background: #FFF; + -moz-border-radius: 0; + -webkit-border-radius: 0; + border-radius: 0; +} +.ui-tabs .ui-tabs-hide { display: none !important; } +/* + * jQuery UI Datepicker 1.8.7 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Datepicker#theming + */ +.ui-datepicker { width: 17em; padding: 0; display: none; border-color: #DDDDDD; } +.ui-datepicker { + -moz-box-shadow: 0 4px 8px rgba(0,0,0,0.5); + -webkit-box-shadow: 0 4px 8px rgba(0,0,0,0.5); + box-shadow: 0 4px 8px rgba(0,0,0,0.5); +} +.ui-datepicker .ui-datepicker-header { position:relative; padding:.35em 0; border: none; border-bottom: 1px solid #B6B6B6; -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; } +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 6px; width: 1.8em; height: 1.8em; } +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { border: 1px none; } +.ui-datepicker .ui-datepicker-prev { left:2px; } +.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev span { background-position: 0px -32px !important; } +.ui-datepicker .ui-datepicker-next span { background-position: -16px -32px !important; } +.ui-datepicker .ui-datepicker-prev-hover span { background-position: 0px -48px !important; } +.ui-datepicker .ui-datepicker-next-hover span { background-position: -16px -48px !important; } +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; background: url(icon_sprite.png) no-repeat; } +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; font-size: 12px; text-shadow: 0 1px 0 rgba(255,255,255,0.6); } +.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;} +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } +.ui-datepicker td { border: 0; padding: 1px; } +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } +.ui-datepicker table .ui-state-highlight { border-color: #5F83B9; } +.ui-datepicker table .ui-state-hover { background: #5F83B9; color: #FFF; font-weight: bold; text-shadow: 0 1px 1px #234386; -webkit-box-shadow: 0 0px 0 rgba(255,255,255,0.6) inset; -moz-box-shadow: 0 0px 0 rgba(255,255,255,0.6) inset; box-shadow: 0 0px 0 rgba(255,255,255,0.6) inset; border-color: #5F83B9; } +.ui-datepicker-calendar .ui-state-default { background: transparent; border-color: #FFF; } +.ui-datepicker-calendar .ui-state-active { background: #5F83B9; border-color: #5F83B9; color: #FFF; font-weight: bold; text-shadow: 0 1px 1px #234386; } + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { width:auto; } +.ui-datepicker-multi .ui-datepicker-group { float:left; } +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } +.ui-datepicker-row-break { clear:both; width:100%; } + +/* RTL support */ +.ui-datepicker-rtl { direction: rtl; } +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } +.ui-datepicker-rtl .ui-datepicker-group { float:right; } +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } + +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ +.ui-datepicker-cover { + display: none; /*sorry for IE5*/ + display/**/: block; /*sorry for IE5*/ + position: absolute; /*must have*/ + z-index: -1; /*must have*/ + filter: mask(); /*must have*/ + top: -4px; /*must have*/ + left: -4px; /*must have*/ + width: 200px; /*must have*/ + height: 200px; /*must have*/ +}/* + * jQuery UI Progressbar 1.8.7 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Progressbar#theming + */ +.ui-progressbar { height: 12px; text-align: left; background: #FFF url(progress_bar.gif) 0 -14px repeat-x; } +.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; background: url(progress_bar.gif) 0 0 repeat-x; } + +/* Extra Input Field Styling */ +.ui-form textarea, .ui-form input:not([type="submit"]):not([type="button"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]) { + padding: 3px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + border: 1px solid #cecece; + outline: none; + -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.1) inset, 0 1px 0 rgba(255,255,255,0.2); + -moz-box-shadow: 0 1px 3px rgba(0,0,0,0.1) inset, 0 1px 0 rgba(255,255,255,0.2); + box-shadow: 0 1px 3px rgba(0,0,0,0.1) inset, 0 1px 0 rgba(255,255,255,0.2); + -webkit-transition: all 250ms ease-in-out; + -moz-transition: all 250ms ease-in-out; + -o-transition: all 250ms ease-in-out; + transition: all 250ms ease-in-out; +} +.ui-form textarea:hover, .ui-form input:not([type="submit"]):not([type="button"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]):hover { + border: 1px solid #bdbdbd; + -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.2) inset, 0 1px 0 rgba(255,255,255,0.2); + -moz-box-shadow: 0 1px 3px rgba(0,0,0,0.2) inset, 0 1px 0 rgba(255,255,255,0.2); + box-shadow: 0 1px 3px rgba(0,0,0,0.2) inset, 0 1px 0 rgba(255,255,255,0.2); +} +.ui-form textarea:focus, .ui-form input:not([type="submit"]):not([type="button"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]):focus { + border: 1px solid #95bdd4; + -webkit-box-shadow: 0 2px 3px rgba(161,202,226,0.5) inset, 0 1px 0 rgba(255,255,255,0.2); + -moz-box-shadow: 0 2px 3px rgba(161,202,226,0.5) inset, 0 1px 0 rgba(255,255,255,0.2); + box-shadow: 0 2px 3px rgba(161,202,226,0.5) inset, 0 1px 0 rgba(255,255,255,0.2); +} |