diff options
Diffstat (limited to 'app')
190 files changed, 2425 insertions, 2270 deletions
diff --git a/app/assets/fonts/OFL.txt b/app/assets/fonts/OFL.txt new file mode 100644 index 00000000000..3ce219f0126 --- /dev/null +++ b/app/assets/fonts/OFL.txt @@ -0,0 +1,92 @@ +Copyright (c) 2010, Jan Gerner (post@yanone.de)
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/app/assets/fonts/YanoneKaffeesatz-Light.ttf b/app/assets/fonts/YanoneKaffeesatz-Light.ttf Binary files differnew file mode 100644 index 00000000000..5026d3bdbe2 --- /dev/null +++ b/app/assets/fonts/YanoneKaffeesatz-Light.ttf diff --git a/app/assets/fonts/korolev-medium-compressed.otf b/app/assets/fonts/korolev-medium-compressed.otf Binary files differdeleted file mode 100644 index a9cd3cbffff..00000000000 --- a/app/assets/fonts/korolev-medium-compressed.otf +++ /dev/null diff --git a/app/assets/images/download.png b/app/assets/images/download.png Binary files differdeleted file mode 100644 index 5791e723de9..00000000000 --- a/app/assets/images/download.png +++ /dev/null diff --git a/app/assets/javascripts/dashboard.js.coffee b/app/assets/javascripts/dashboard.js.coffee new file mode 100644 index 00000000000..b0ae6bf8a02 --- /dev/null +++ b/app/assets/javascripts/dashboard.js.coffee @@ -0,0 +1,30 @@ +$ -> + dashboardPage() + +dashboardPage = -> + Pager.init 20, true + $(".event_filter_link").bind "click", (event) -> + event.preventDefault() + toggleFilter $(this) + reloadActivities() + +reloadActivities = -> + $(".content_list").html '' + Pager.init 20, true + +toggleFilter = (sender) -> + sender.parent().toggleClass "inactive" + event_filters = $.cookie("event_filter") + filter = sender.attr("id").split("_")[0] + if event_filters + event_filters = event_filters.split(",") + else + event_filters = new Array() + + index = event_filters.indexOf(filter) + if index is -1 + event_filters.push filter + else + event_filters.splice index, 1 + + $.cookie "event_filter", event_filters.join(",") diff --git a/app/assets/javascripts/issues.js b/app/assets/javascripts/issues.js index 719d2c176c1..9ba1a3f1bba 100644 --- a/app/assets/javascripts/issues.js +++ b/app/assets/javascripts/issues.js @@ -11,7 +11,7 @@ function initIssuesSearch() { last_terms = terms; if (terms.length >= 2 || terms.length == 0) { - $.get(href, { 'f': status, 'terms': terms, 'milestone_id': milestone_id }, function(response) { + $.get(href, { 'status': status, 'terms': terms, 'milestone_id': milestone_id }, function(response) { $('#issues-table').html(response); }); } diff --git a/app/assets/javascripts/merge_requests.js b/app/assets/javascripts/merge_requests.js deleted file mode 100644 index ee714f9cabb..00000000000 --- a/app/assets/javascripts/merge_requests.js +++ /dev/null @@ -1,132 +0,0 @@ -var MergeRequest = { - diffs_loaded: false, - commits_loaded: false, - opts: false, - - init: - function(opts) { - var self = this; - self.opts = opts; - - self.initTabs(); - self.initMergeWidget(); - - $(".mr_show_all_commits").bind("click", function() { - self.showAllCommits(); - }); - }, - - initMergeWidget: - function() { - var self = this; - self.showState(self.opts.current_state); - - if($(".automerge_widget").length && self.opts.check_enable){ - $.get(self.opts.url_to_automerge_check, function(data){ - self.showState(data.state); - }, "json"); - } - - if(self.opts.ci_enable){ - $.get(self.opts.url_to_ci_check, function(data){ - self.showCiState(data.status); - }, "json"); - } - }, - - initTabs: - function() { - $(".mr_nav_tabs a").live("click", function() { - $(".mr_nav_tabs a").parent().removeClass("active"); - $(this).parent().addClass("active"); - }); - - var current_tab; - if(this.opts.action == "diffs") { - current_tab = $(".mr_nav_tabs .merge-diffs-tab"); - } else { - current_tab = $(".mr_nav_tabs .merge-notes-tab"); - } - current_tab.parent().addClass("active"); - - this.initNotesTab(); - this.initDiffTab(); - }, - - initNotesTab: - function() { - $(".mr_nav_tabs a.merge-notes-tab").live("click", function(e) { - $(".merge-request-diffs").hide(); - $(".merge_request_notes").show(); - var mr_path = $(".merge-notes-tab").attr("data-url"); - history.pushState({ path: mr_path }, '', mr_path); - e.preventDefault(); - }); - }, - - initDiffTab: - function() { - $(".mr_nav_tabs a.merge-diffs-tab").live("click", function(e) { - if(!MergeRequest.diffs_loaded) { - MergeRequest.loadDiff(); - } - $(".merge_request_notes").hide(); - $(".merge-request-diffs").show(); - var mr_diff_path = $(".merge-diffs-tab").attr("data-url"); - history.pushState({ path: mr_diff_path }, '', mr_diff_path); - e.preventDefault(); - }); - - }, - - showState: - function(state){ - $(".automerge_widget").hide(); - $(".automerge_widget." + state).show(); - }, - - showCiState: - function(state){ - $(".ci_widget").hide(); - $(".ci_widget.ci-" + state).show(); - }, - - loadDiff: - function() { - $(".dashboard-loader").show(); - $.ajax({ - type: "GET", - url: $(".merge-diffs-tab").attr("data-url"), - beforeSend: function(){ $('.status').addClass("loading")}, - complete: function(){ - MergeRequest.diffs_loaded = true; - $(".merge_request_notes").hide(); - $('.status').removeClass("loading"); - }, - dataType: "script"}); - }, - - showAllCommits: - function() { - $(".first_mr_commits").remove(); - $(".all_mr_commits").removeClass("hide"); - }, - - already_cannot_be_merged: - function(){ - $(".automerge_widget").hide(); - $(".merge_in_progress").hide(); - $(".automerge_widget.already_cannot_be_merged").show(); - } -}; - -/* - * Filter merge requests - */ -function merge_requestsPage() { - $("#assignee_id").chosen(); - $("#milestone_id").chosen(); - $("#milestone_id, #assignee_id").on("change", function(){ - $(this).closest("form").submit(); - }); -} diff --git a/app/assets/javascripts/merge_requests.js.coffee b/app/assets/javascripts/merge_requests.js.coffee new file mode 100644 index 00000000000..cdc685f2c09 --- /dev/null +++ b/app/assets/javascripts/merge_requests.js.coffee @@ -0,0 +1,97 @@ +# +# * Filter merge requests +# +@merge_requestsPage = -> + $('#assignee_id').chosen() + $('#milestone_id').chosen() + $('#milestone_id, #assignee_id').on 'change', -> + $(this).closest('form').submit() + +class MergeRequest + + constructor: (@opts) -> + this.$el = $('.merge-request') + @diffs_loaded = false + @commits_loaded = false + + this.activateTab(@opts.action) + + this.bindEvents() + + this.initMergeWidget() + this.$('.show-all-commits').on 'click', => + this.showAllCommits() + + # Local jQuery finder + $: (selector) -> + this.$el.find(selector) + + initMergeWidget: -> + this.showState( @opts.current_state ) + + if this.$('.automerge_widget').length and @opts.check_enable + $.get @opts.url_to_automerge_check, (data) => + this.showState( data.state ) + , 'json' + + if @opts.ci_enable + $.get @opts.url_to_ci_check, (data) => + this.showCiState data.status + , 'json' + + bindEvents: -> + this.$('.nav-tabs').on 'click', 'a', (event) => + a = $(event.currentTarget) + + href = a.attr('href') + History.replaceState {path: href}, document.title, href + + event.preventDefault() + + this.$('.nav-tabs').on 'click', 'li', (event) => + this.activateTab($(event.currentTarget).data('action')) + + activateTab: (action) -> + this.$('.nav-tabs li').removeClass 'active' + this.$('.tab-content').hide() + switch action + when 'diffs' + this.$('.nav-tabs .diffs-tab').addClass 'active' + this.loadDiff() unless @diffs_loaded + this.$('.diffs').show() + else + this.$('.nav-tabs .notes-tab').addClass 'active' + this.$('.notes').show() + + showState: (state) -> + $('.automerge_widget').hide() + $('.automerge_widget.' + state).show() + + showCiState: (state) -> + $('.ci_widget').hide() + $('.ci_widget.ci-' + state).show() + + loadDiff: (event) -> + $('.dashboard-loader').show() + $.ajax + type: 'GET' + url: this.$('.nav-tabs .diffs-tab a').attr('href') + beforeSend: => + this.$('.status').addClass 'loading' + + complete: => + @diffs_loaded = true + this.$('.status').removeClass 'loading' + + dataType: 'script' + + showAllCommits: -> + this.$('.first-commits').remove() + this.$('.all-commits').removeClass 'hide' + + alreadyOrCannotBeMerged: -> + this.$('.automerge_widget').hide() + this.$('.merge-in-progress').hide() + this.$('.automerge_widget.already_cannot_be_merged').show() + +this.MergeRequest = MergeRequest diff --git a/app/assets/javascripts/milestones.js.coffee b/app/assets/javascripts/milestones.js.coffee index e40a69ebaa5..99a52bf4d3f 100644 --- a/app/assets/javascripts/milestones.js.coffee +++ b/app/assets/javascripts/milestones.js.coffee @@ -1,14 +1,14 @@ $ -> - $('.milestone-issue-filter tr[data-closed]').addClass('hide') + $('.milestone-issue-filter li[data-closed]').addClass('hide') $('.milestone-issue-filter ul.nav li a').click -> $('.milestone-issue-filter li').toggleClass('active') - $('.milestone-issue-filter tr[data-closed]').toggleClass('hide') + $('.milestone-issue-filter li[data-closed]').toggleClass('hide') false - $('.milestone-merge-requests-filter tr[data-closed]').addClass('hide') + $('.milestone-merge-requests-filter li[data-closed]').addClass('hide') $('.milestone-merge-requests-filter ul.nav li a').click -> $('.milestone-merge-requests-filter li').toggleClass('active') - $('.milestone-merge-requests-filter tr[data-closed]').toggleClass('hide') + $('.milestone-merge-requests-filter li[data-closed]').toggleClass('hide') false diff --git a/app/assets/javascripts/pager.js b/app/assets/javascripts/pager.js index 769e8a62343..7edd6bd6186 100644 --- a/app/assets/javascripts/pager.js +++ b/app/assets/javascripts/pager.js @@ -4,9 +4,16 @@ var Pager = { disable:false, init: - function(limit) { + function(limit, preload) { this.limit=limit; - this.offset=limit; + + if(preload) { + this.offset = 0; + this.getOld(); + } else { + this.offset = limit; + } + this.initLoadMore(); }, diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index 6d4c815106b..e192bb426a1 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -117,34 +117,10 @@ span.update-author { } .label { - background-color: #474D57; - - &.label-tag { - background: none; - border: none; - padding: 4px 6px; - color: #444; - text-shadow: 0 0 1px #fff; - - &.grouped { - float: left; - margin-right: 6px; - padding: 6px; - } - } - &.label-issue { - background-color: #eee; - border: 1px solid #ccc; - padding: 4px 6px; - color: #444; - text-shadow: 0 0 1px #fff; - - &.grouped { - float: left; - margin-right: 6px; - padding: 6px; - } - } + padding: 0px 4px; + font-size: 10px; + font-style: normal; + background-color: $link_color; &.label-success { background-color: #8D8; @@ -425,7 +401,7 @@ li.note { .supp_diff_link, -.mr_show_all_commits { +.show-all-commits { cursor: pointer; } diff --git a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss index f9c8b7b05ea..8cb1c045778 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss @@ -1,23 +1,24 @@ /** * =================================== - * Contain 3 main UI block elements: - * .main_box - for show pages - * .ui-box - for simple block & widgets + * Contain UI block elements: + * .ui-box - for any block & widgets * =================================== */ /** - * UI box element - * contains top, middle, bottom blocks + * UI Block * */ -.main_box { - @extend .borders; - @extend .prepend-top-20; - @extend .append-bottom-20; - border-width: 1px; +.ui-box { + background: #F9F9F9; + margin-bottom: 25px; + border: 1px solid #CCC; @include solid-shade; + &.ui-box-show { + margin:20px 0; + background: #FFF; + } img { max-width: 100%; } @@ -27,9 +28,9 @@ } } - .top_box_content, - .middle_box_content, - .bottom_box_content { + .ui-box-head, + .ui-box-body, + .ui-box-bottom { padding: 15px; word-wrap: break-word; @@ -39,19 +40,25 @@ border: none; padding: 0; } + + .clearfix { + margin: 0; + } } - .top_box_content { + .ui-box-head { .box-title { color: $style_color; font-size: 18px; font-weight: normal; line-height: 28px; } + h3 { + margin: 0; + } } - .middle_box_content { - @include border-radius(0); + .ui-box-body { border: none; font-size: 12px; background-color: #f5f5f5; @@ -59,24 +66,9 @@ border-top: 1px solid #eee; } - .bottom_box_content { + .ui-box-bottom { border-top: 1px solid #eee; } -} - -/** - * Big UI Block for show page content - * - */ -.ui-box { - background: #F9F9F9; - margin-bottom: 25px; - - border: 1px solid #eaeaea; - @include border-radius(4px); - - border-color: #CCC; - @include solid-shade; &.white { background: #fff; @@ -86,47 +78,47 @@ margin: 0; } - h5, .title { - padding: 0 10px; - @include border-radius(4px 4px 0 0); + .title { @include bg-gray-gradient; - border-top: 1px solid #eaeaea; - border-bottom: 1px solid #bbb; + border-bottom: 1px solid #CCC; + color: #456; + font-size: 16px; + text-shadow: 0 1px 1px #fff; + padding: 0px 10px; + line-height: 36px; + font-size: 14px; + font-weight: normal; > a { text-shadow: 0 1px 1px #fff; } - &.small { - line-height: 28px; - font-size: 14px; - line-height: 28px; - text-shadow: 0 1px 1px white; - } - form { - padding: 9px 0; - margin: 0px; + margin-bottom: 0; + margin-top: 3px; } .nav-pills { - li { - padding: 3px 0; - &.active a { background-color: $style_color; } - a { - @include border-radius(7px); + > li { + > a { + padding: 13px; + margin: 0; + font-size: 13px; + } + &.active { + > a { + background: #D5D5D5; + color: $style_color; + @include border-radius(0); + border-radius: 0; + border-left: 1px solid #CCC; + border-right: 1px solid #CCC; + } } } } } - .bottom { - @include bg-gray-gradient; - @include border-radius(0 0 4px 4px); - border-bottom: none; - border-top: 1px solid #bbb; - } - &.padded { h5, .title { margin: -20px; @@ -143,6 +135,7 @@ color: #777; } } + .row_title { font-weight: bold; color: #444; @@ -151,8 +144,4 @@ text-decoration: underline; } } - - .ui-box-body { - padding: 10px; - } } diff --git a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss index 883a8773962..2b5ecce4246 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss @@ -7,6 +7,10 @@ color: #333; } + &.btn-white { + background: #FFF; + } + &.primary { background: #2a79A3; @include linear-gradient(#47A7b7, #2585b5); diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss index 3bb7cdbf706..f088766afbd 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/common.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss @@ -17,20 +17,43 @@ .padded { padding:20px } .ipadded { padding:20px!important } .lborder { border-left:1px solid #eee } -.no-padding { padding:0 !important; } -.underlined { border-bottom: 1px solid #CCC; } -.no-borders { border: none; } -.vlink { color: $link_color !important; } .underlined_link { text-decoration: underline; } -.borders { border: 1px solid #ccc; @include shade; } .hint { font-style: italic; color: #999; } .light { color: #888 } .tiny { font-weight: normal } /** PILLS & TABS**/ -.nav-pills a:hover { background-color: #888; } -.nav-pills .active a { background-color: $style_color; } +.nav-pills { + .active a { + background: $primary_color; + } + + > li > a { + @include border-radius(0); + } + &.nav-stacked { + > li > a { + border-left: 4px solid #EEE; + padding: 12px; + } + > .active > a { + border-color: #29B; + border-radius: 0; + background: #F1F1F1; + color: $style_color; + font-weight: bold; + } + } +} + .nav-pills > .active > a > i[class^="icon-"] { background: inherit; } + + + +/** + * nav-tabs + * + */ .nav-tabs > li > a, .nav-pills > li > a { color: $style_color; } .nav.nav-tabs { li { diff --git a/app/assets/stylesheets/gitlab_bootstrap/fonts.scss b/app/assets/stylesheets/gitlab_bootstrap/fonts.scss index 88c966d18f7..b4217fa9cfa 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/fonts.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/fonts.scss @@ -1,7 +1,7 @@ -@font-face{ - font-family: Korolev; - src: font-url('korolev-medium-compressed.otf'); +@font-face{ + font-family: Yanone; + src: font-url('YanoneKaffeesatz-Light.ttf'); } /** Typo **/ -$monospace: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace;
\ No newline at end of file +$monospace: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace; diff --git a/app/assets/stylesheets/gitlab_bootstrap/lists.scss b/app/assets/stylesheets/gitlab_bootstrap/lists.scss index edaf3cef2cf..0f893a553ee 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/lists.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/lists.scss @@ -23,14 +23,12 @@ border-bottom: 1px solid #ADF; } - &:first-child { - @include border-radius(4px 4px 0 0); - border-top: none; - } - &:last-child { - @include border-radius(0 0 4px 4px); - border: none; + border-bottom: none; + + &.bottom { + background: #f5f5f5; + } } .author { color: #999; } diff --git a/app/assets/stylesheets/gitlab_bootstrap/mixins.scss b/app/assets/stylesheets/gitlab_bootstrap/mixins.scss index 81830368c4c..9b1e2f2c728 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/mixins.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/mixins.scss @@ -62,8 +62,8 @@ @mixin header-font { color: $style_color; text-shadow: 0 1px 1px #FFF; - font-family: 'Korolev', sans-serif; - font-size: 28px; - line-height: 48px; + font-family: 'Yanone', sans-serif; + font-size: 26px; + line-height: 42px; font-weight: normal; } diff --git a/app/assets/stylesheets/gitlab_bootstrap/tables.scss b/app/assets/stylesheets/gitlab_bootstrap/tables.scss index 5905efd3aae..7a9eac82566 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/tables.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/tables.scss @@ -25,7 +25,7 @@ table { } th, td { - padding: 8px; + padding: 10px; line-height: 18px; text-align: left; } diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss index 1cae7b0c6b1..c60aae49eaa 100644 --- a/app/assets/stylesheets/sections/commits.scss +++ b/app/assets/stylesheets/sections/commits.scss @@ -1,74 +1,17 @@ -.commit-box { - @extend .main_box; - - .commit-head { - @extend .top_box_content; - - .commit-title { - line-height: 26px; - margin: 0; - } - - .commit-description { - font-size: 14px; - border: none; - background-color: white; - padding-top: 10px; - } - - .browse-button { - @extend .btn; - @extend .btn-small; - float: right; - } - } - - .commit-info { - @extend .middle_box_content; - @extend .clearfix; - - .sha-block { - text-align: right; - &:first-child { - padding-bottom: 6px; - } - - a { - border-bottom: 1px solid #aaa; - margin-left: 9px; - } - } - - &.merge-commit .sha-block { - clear: right; - } - - .committer { - padding-left: 32px; - } - - .author a, - .committer a { - font-size: 14px; - line-height: 22px; - text-shadow: 0 1px 1px #fff; - color: #777; - &:hover { - color: #999; - } - } - - .avatar { - margin-right: 10px; - } - } -} - /** * * COMMIT SHOw * */ +.commit-committer-link, +.commit-author-link { + font-size: 13px; + color: #555; + &:hover { + color: #999; + } +} + .diff_file { border: 1px solid #CCC; margin-bottom: 1em; @@ -258,13 +201,6 @@ min-width: 65px; font-family: $monospace; } - - .commit-author-name { - color: #777; - &:hover { - color: #999; - } - } } .diff_file_header a, diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss index 071a9c35468..2d41de25103 100644 --- a/app/assets/stylesheets/sections/events.scss +++ b/app/assets/stylesheets/sections/events.scss @@ -47,6 +47,12 @@ .event-info { color: #666; } + .event-note { + padding-top: 5px; + padding-left: 5px; + display: inline-block; + color: #777; + } } .avatar { position: relative; diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss index c1b210be1ab..048a3ffcbb2 100644 --- a/app/assets/stylesheets/sections/header.scss +++ b/app/assets/stylesheets/sections/header.scss @@ -33,22 +33,29 @@ header { * */ .app_logo { - width: 170px; float: left; + margin-right: 15px; + position: relative; + top: -5px; + padding-top: 5px; + a { float: left; padding: 0px; + margin: 0 10px; h1 { - width: 90px; background: url('logo_dark.png') no-repeat 0px 2px; float: left; - margin-left: 2px; - padding-left: 45px; height: 40px; + width: 40px; @include header-font; + text-indent: -9999px; } } + &:hover { + background-color: #EEE; + } } /** @@ -60,7 +67,7 @@ header { position: relative; float: left; margin: 0; - margin-right: 30px; + margin-left: 15px; @include header-font; } @@ -233,7 +240,7 @@ header { .app_logo { a { h1 { - background: url('logo_white.png') no-repeat 0px 2px; + background: url('logo_white.png') no-repeat center center; color: #fff; text-shadow: 0 1px 1px #111; } @@ -244,5 +251,23 @@ header { text-shadow: 0 1px 1px #111; } } + + .app_logo { + .separator { + margin-left: 0; + margin-right: 0; + } + } + + .separator { + float: left; + height: 60px; + width: 1px; + background: white; + border-left: 1px solid #DDD; + margin-top: -10px; + margin-left: 10px; + margin-right: 10px; + } } diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss index fd995728978..351f2404492 100644 --- a/app/assets/stylesheets/sections/issues.scss +++ b/app/assets/stylesheets/sections/issues.scss @@ -1,34 +1,6 @@ -.issue_form_box { - @extend .main_box; - .issue_title { - @extend .top_box_content; - .clearfix { - margin-bottom: 0px; - input { - @extend .span8; - } - } - } - .issue_middle_block { - @extend .middle_box_content; - height: 30px; - .issue_assignee { - @extend .span6; - float: left; - } - .issue_milestone { - @extend .span4; - float: left; - } - } - .issue_description { - @extend .bottom_box_content; - } -} - .issues_table { .issue { - padding: 7px 10px; + padding: 10px; .issue_check { float: left; @@ -82,38 +54,34 @@ input.check_all_issues { } } -@media (min-width: 800px) { .issues_filters select { width: 160px; } } -@media (min-width: 1000px) { .issues_filters select { width: 200px; } } +@media (min-width: 800px) { .issues_filters select { width: 160px; } } @media (min-width: 1200px) { .issues_filters select { width: 220px; } } +@media (min-width: 800px) { .issues_bulk_update select { width: 120px; } } +@media (min-width: 1200px) { .issues_bulk_update select { width: 160px; } } #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 + float:left; } + .update_selected_issues { position: relative; - top:-2px; + top:5px; margin-left: 4px; float: left; } .update_issues_text { padding: 3px; - line-height: 18px; + line-height: 28px; float: left; + color: #479; } } } diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss index 4808117d02a..5225a242726 100644 --- a/app/assets/stylesheets/sections/merge_requests.scss +++ b/app/assets/stylesheets/sections/merge_requests.scss @@ -1,17 +1,3 @@ -/** - * MR form - * - */ - -.mr_branch_box { - @extend .ui-box; - margin-bottom: 20px; - - .body { - background: #f1f1f1; - } - -} /** * MR -> show: Automerge widget @@ -47,6 +33,7 @@ } label { color: #444; + text-align: left } } @@ -56,7 +43,7 @@ } } -.mr_nav_tabs { +.merge-request .nav-tabs{ li { a { font-weight: bold; @@ -67,7 +54,7 @@ } li.merge_request { - padding: 7px 10px; + padding: 10px; img.avatar { width: 32px; margin-top: 1px; @@ -78,7 +65,7 @@ li.merge_request { } } -.merge_in_progress { +.merge-in-progress { @extend .padded; @extend .append-bottom-10; } @@ -120,19 +107,3 @@ li.merge_request { .mr_direction_tip { margin-top:40px } - -.merge_requests_form_box { - @extend .main_box; - .merge_requests_middle_box { - @extend .middle_box_content; - height: 30px; - .merge_requests_assignee { - @extend .span6; - float: left; - } - .merge_requests_milestone { - @extend .span4; - float: left; - } - } -} diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index 465d578f3b7..93ad0d45037 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -294,6 +294,8 @@ ul.notes { padding: 4px 6px; } .note_text { + border: 1px solid #DDD; + box-shadow: none; font-size: 14px; height: 80px; width: 98.6%; diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss index 717f85024cc..072ade80ad3 100644 --- a/app/assets/stylesheets/sections/projects.scss +++ b/app/assets/stylesheets/sections/projects.scss @@ -8,16 +8,12 @@ .groups_box, .projects_box { - > h5 { - color: $style_color; - font-size: 16px; - text-shadow: 0 1px 1px #fff; - padding: 2px 10px; - line-height: 32px; - font-size: 14px; + > .title { + padding: 2px 15px; } .nav-projects-tabs li { padding: 0; } .well-list { + li { padding: 15px; } .arrow { float: right; padding: 10px; @@ -109,7 +105,7 @@ ul.nav.nav-projects-tabs { li { a { - padding: 4px 20px; + padding: 6px 25px; margin-top: 2px; border-color: #DDD; background-color: #EEE; diff --git a/app/assets/stylesheets/themes/ui_basic.scss b/app/assets/stylesheets/themes/ui_basic.scss index b377727779a..4e34e8b1b6b 100644 --- a/app/assets/stylesheets/themes/ui_basic.scss +++ b/app/assets/stylesheets/themes/ui_basic.scss @@ -4,21 +4,8 @@ * */ .ui_basic { - .app_logo { - .separator { - margin-left: 0; - margin-right: 0; - } - } - .separator { - float: left; - height: 60px; - width: 1px; background: white; border-left: 1px solid #DDD; - margin-top: -10px; - margin-left: 10px; - margin-right: 10px; } } diff --git a/app/assets/stylesheets/themes/ui_color.scss b/app/assets/stylesheets/themes/ui_color.scss index 8c60fabb3a7..d7a554ff9e5 100644 --- a/app/assets/stylesheets/themes/ui_color.scss +++ b/app/assets/stylesheets/themes/ui_color.scss @@ -17,6 +17,15 @@ &.navbar-gitlab { .navbar-inner { background: #657; + .app_logo { + &:hover { + background-color: #6A5A7A; + } + } + .separator { + background: #546; + border-left: 1px solid #706080; + } } } } diff --git a/app/assets/stylesheets/themes/ui_gray.scss b/app/assets/stylesheets/themes/ui_gray.scss index e80137a69c8..f0547c72157 100644 --- a/app/assets/stylesheets/themes/ui_gray.scss +++ b/app/assets/stylesheets/themes/ui_gray.scss @@ -17,6 +17,15 @@ &.navbar-gitlab { .navbar-inner { background: #708090; + .app_logo { + &:hover { + background-color: #6A7A8A; + } + } + .separator { + background: #607080; + border-left: 1px solid #8090A0; + } } } } diff --git a/app/assets/stylesheets/themes/ui_mars.scss b/app/assets/stylesheets/themes/ui_mars.scss index 9e6433c5f9e..0a78c5c09f5 100644 --- a/app/assets/stylesheets/themes/ui_mars.scss +++ b/app/assets/stylesheets/themes/ui_mars.scss @@ -46,21 +46,26 @@ .app_logo { a { h1 { - background: url('logo_white.png') no-repeat 0px 2px; + background: url('logo_white.png') no-repeat center center; color: #eee; text-shadow: 0 1px 1px #111; } } - .separator { - display: none; + &:hover { + background-color: #41464e; } - } .project_name { color: #eee; text-shadow: 0 1px 1px #111; } } + + .separator { + background: #31363E; + border-left: 1px solid #666; + } + /* * End of Application Header * diff --git a/app/assets/stylesheets/themes/ui_modern.scss b/app/assets/stylesheets/themes/ui_modern.scss index 32b5ad7d968..a5bf414c443 100644 --- a/app/assets/stylesheets/themes/ui_modern.scss +++ b/app/assets/stylesheets/themes/ui_modern.scss @@ -17,6 +17,15 @@ &.navbar-gitlab { .navbar-inner { background: #567; + .app_logo { + &:hover { + background-color: #516171; + } + } + .separator { + background: #456; + border-left: 1px solid #678; + } } } } diff --git a/app/contexts/commit_load_context.rb b/app/contexts/commit_load_context.rb index e43e5a07805..1f23f633af3 100644 --- a/app/contexts/commit_load_context.rb +++ b/app/contexts/commit_load_context.rb @@ -9,16 +9,16 @@ class CommitLoadContext < BaseContext status: :ok } - commit = project.commit(params[:id]) + commit = project.repository.commit(params[:id]) if commit commit = CommitDecorator.decorate(commit) - line_notes = project.commit_line_notes(commit) + line_notes = project.notes.for_commit_id(commit.id).inline 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 + result[:notes_count] = project.notes.for_commit_id(commit.id).count begin result[:suppress_diff] = true if commit.diffs.size > Commit::DIFF_SAFE_SIZE && !params[:force_show_diff] diff --git a/app/contexts/filter_context.rb b/app/contexts/filter_context.rb new file mode 100644 index 00000000000..401d19b31c8 --- /dev/null +++ b/app/contexts/filter_context.rb @@ -0,0 +1,31 @@ +class FilterContext + attr_accessor :items, :params + + def initialize(items, params) + @items = items + @params = params + end + + def execute + apply_filter(items) + end + + def apply_filter items + if params[:project_id] + items = items.where(project_id: params[:project_id]) + end + + if params[:search].present? + items = items.search(params[:search]) + end + + case params[:status] + when 'closed' + items.closed + when 'all' + items + else + items.opened + end + end +end diff --git a/app/contexts/issues_list_context.rb b/app/contexts/issues_list_context.rb index 9bbdfe1db39..0cc73f99535 100644 --- a/app/contexts/issues_list_context.rb +++ b/app/contexts/issues_list_context.rb @@ -4,7 +4,7 @@ class IssuesListContext < BaseContext attr_accessor :issues def execute - @issues = case params[:f] + @issues = case params[:status] when issues_filter[:all] then @project.issues when issues_filter[:closed] then @project.issues.closed when issues_filter[:to_me] then @project.issues.opened.assigned(current_user) diff --git a/app/contexts/notes/load_context.rb b/app/contexts/notes/load_context.rb index 4e2f35040fd..e3875e1d4e2 100644 --- a/app/contexts/notes/load_context.rb +++ b/app/contexts/notes/load_context.rb @@ -9,7 +9,7 @@ module Notes @notes = case target_type when "commit" - project.commit_notes(project.commit(target_id)).fresh + project.notes.for_commit_id(target_id).not_inline.fresh when "issue" project.issues.find(target_id).notes.inc_author.fresh when "merge_request" @@ -18,7 +18,7 @@ module Notes project.snippets.find(target_id).notes.fresh when "wall" # this is the only case, where the order is DESC - project.common_notes.order("created_at DESC, id DESC").limit(50) + project.notes.common.inc_author_project.order("created_at DESC, id DESC").limit(50) end @notes = if after_id diff --git a/app/contexts/test_hook_context.rb b/app/contexts/test_hook_context.rb index cba5d1f87c2..d2d82a52cf5 100644 --- a/app/contexts/test_hook_context.rb +++ b/app/contexts/test_hook_context.rb @@ -1,7 +1,7 @@ class TestHookContext < BaseContext def execute hook = project.hooks.find(params[:id]) - commits = project.commits(project.default_branch, nil, 3) + commits = project.repository.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 diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb index 827dd0cf7cd..f97c56b0b31 100644 --- a/app/controllers/admin/dashboard_controller.rb +++ b/app/controllers/admin/dashboard_controller.rb @@ -3,10 +3,6 @@ class Admin::DashboardController < AdminController @projects = Project.order("created_at DESC").limit(10) @users = User.order("created_at DESC").limit(10) - @resque_accessible = true - @workers = Resque.workers - @pending_jobs = Resque.size(:post_receive) - rescue Redis::InheritedError @resque_accessible = false end diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb index a492e66611f..90dbda3eeea 100644 --- a/app/controllers/admin/groups_controller.rb +++ b/app/controllers/admin/groups_controller.rb @@ -1,5 +1,5 @@ class Admin::GroupsController < AdminController - before_filter :group, only: [:edit, :show, :update, :destroy, :project_update] + before_filter :group, only: [:edit, :show, :update, :destroy, :project_update, :project_teams_update] def index @groups = Group.order('name ASC') @@ -12,6 +12,8 @@ class Admin::GroupsController < AdminController @projects = @projects.not_in_group(@group) if @group.projects.present? @projects = @projects.all @projects.reject!(&:empty_repo?) + + @users = User.active end def new @@ -65,7 +67,14 @@ class Admin::GroupsController < AdminController redirect_to :back, notice: 'Group was successfully updated.' end + def project_teams_update + @group.add_users_to_project_teams(params[:user_ids], params[:project_access]) + redirect_to [:admin, @group], notice: 'Users was successfully added.' + end + def destroy + @group.truncate_teams + @group.destroy redirect_to admin_groups_path, notice: 'Group was successfully deleted.' diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb index 4fea8709b70..d5e6f3cdc0e 100644 --- a/app/controllers/admin/projects_controller.rb +++ b/app/controllers/admin/projects_controller.rb @@ -10,6 +10,7 @@ class Admin::ProjectsController < AdminController end def show + @repository = @project.repository @users = User.active @users = @users.not_in_project(@project) if @project.users.present? @users = @users.all @@ -19,7 +20,7 @@ class Admin::ProjectsController < AdminController end def team_update - @project.add_users_ids_to_team(params[:user_ids], params[:project_access]) + @project.team.add_users_ids(params[:user_ids], params[:project_access]) redirect_to [:admin, @project], notice: 'Project was successfully updated.' end @@ -35,6 +36,9 @@ class Admin::ProjectsController < AdminController end def destroy + # Delete team first in order to prevent multiple gitolite calls + @project.team.truncate + @project.destroy redirect_to admin_projects_path, notice: 'Project was successfully deleted.' diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 5f259bd7e27..8669f5d1d38 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -3,13 +3,13 @@ class Admin::UsersController < AdminController @admin_users = User.scoped @admin_users = @admin_users.filter(params[:filter]) @admin_users = @admin_users.search(params[:name]) if params[:name].present? - @admin_users = @admin_users.order("name ASC").page(params[:page]) + @admin_users = @admin_users.alphabetically.page(params[:page]) end def show @admin_user = User.find(params[:id]) - @projects = if @admin_user.projects.empty? + @projects = if @admin_user.authorized_projects.empty? Project else Project.without_user(@admin_user) @@ -19,9 +19,9 @@ class Admin::UsersController < AdminController def team_update @admin_user = User.find(params[:id]) - UsersProject.user_bulk_import( - @admin_user, + UsersProject.add_users_into_projects( params[:project_ids], + [@admin_user.id], params[:project_access] ) @@ -98,7 +98,7 @@ class Admin::UsersController < AdminController def destroy @admin_user = User.find(params[:id]) - if @admin_user.my_own_projects.count > 0 + if @admin_user.personal_projects.count > 0 redirect_to admin_users_path, alert: "User is a project owner and can't be removed." and return end @admin_user.destroy diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 75cd8f15605..3457a1ab1b4 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -76,6 +76,12 @@ class ApplicationController < ActionController::Base end end + def repository + @repository ||= project.repository + rescue Grit::NoSuchPathError + nil + end + def add_abilities abilities << Ability end diff --git a/app/controllers/commits_controller.rb b/app/controllers/commits_controller.rb index 3b8ebdb5ddc..534ae1edd31 100644 --- a/app/controllers/commits_controller.rb +++ b/app/controllers/commits_controller.rb @@ -9,10 +9,10 @@ class CommitsController < ProjectResourceController before_filter :require_non_empty_project def show - @repo = @project.repo + @repo = @project.repository @limit, @offset = (params[:limit] || 40), (params[:offset] || 0) - @commits = @project.commits(@ref, @path, @limit, @offset) + @commits = @repo.commits(@ref, @path, @limit, @offset) @commits = CommitDecorator.decorate(@commits) respond_to do |format| diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 1fcadbfefba..c0ec4708e0a 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -20,7 +20,7 @@ class DashboardController < ApplicationController @projects = @projects.page(params[:page]).per(30) - @events = Event.in_projects(current_user.project_ids) + @events = Event.in_projects(current_user.authorized_projects.pluck(:id)) @events = @event_filter.apply_filter(@events) @events = @events.limit(20).offset(params[:offset] || 0) @@ -36,14 +36,14 @@ class DashboardController < ApplicationController # Get authored or assigned open merge requests def merge_requests @merge_requests = current_user.cared_merge_requests - @merge_requests = dashboard_filter(@merge_requests) + @merge_requests = FilterContext.new(@merge_requests, params).execute @merge_requests = @merge_requests.recent.page(params[:page]).per(20) end # Get only assigned issues def issues @issues = current_user.assigned_issues - @issues = dashboard_filter(@issues) + @issues = FilterContext.new(@issues, params).execute @issues = @issues.recent.page(params[:page]).per(20) @issues = @issues.includes(:author, :project) @@ -60,25 +60,7 @@ class DashboardController < ApplicationController end def event_filter - @event_filter ||= EventFilter.new(params[:event_filter]) - end - - def dashboard_filter items - if params[:project_id] - items = items.where(project_id: params[:project_id]) - end - - if params[:search].present? - items = items.search(params[:search]) - end - - case params[:status] - when 'closed' - items.closed - when 'all' - items - else - items.opened - end + filters = cookies['event_filter'].split(',') if cookies['event_filter'] + @event_filter ||= EventFilter.new(filters) end end diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index c82edb4c168..c25fc32a62c 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -21,15 +21,16 @@ class GroupsController < ApplicationController # Get authored or assigned open merge requests def merge_requests - @merge_requests = current_user.cared_merge_requests.opened - @merge_requests = @merge_requests.of_group(@group).recent.page(params[:page]).per(20) + @merge_requests = current_user.cared_merge_requests.of_group(@group) + @merge_requests = FilterContext.new(@merge_requests, params).execute + @merge_requests = @merge_requests.recent.page(params[:page]).per(20) end # Get only assigned issues def issues - @user = current_user - @issues = current_user.assigned_issues.opened - @issues = @issues.of_group(@group).recent.page(params[:page]).per(20) + @issues = current_user.assigned_issues.of_group(@group) + @issues = FilterContext.new(@issues, params).execute + @issues = @issues.recent.page(params[:page]).per(20) @issues = @issues.includes(:author, :project) respond_to do |format| @@ -44,6 +45,7 @@ class GroupsController < ApplicationController @projects = result[:projects] @merge_requests = result[:merge_requests] @issues = result[:issues] + @wiki_pages = result[:wiki_pages] end def people @@ -53,9 +55,16 @@ class GroupsController < ApplicationController if @project @team_member = @project.users_projects.new + else + @team_member = UsersProject.new end end + def team_members + @group.add_users_to_project_teams(params[:user_ids], params[:project_access]) + redirect_to people_group_path(@group), notice: 'Users was successfully added.' + end + protected def group @@ -63,7 +72,7 @@ class GroupsController < ApplicationController end def projects - @projects ||= group.projects.authorized_for(current_user).sorted_by_activity + @projects ||= current_user.authorized_projects.where(namespace_id: group.id).sorted_by_activity end def project_ids diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index 355f4d79d67..ab6bf595982 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -74,6 +74,8 @@ class MergeRequestsController < ProjectResourceController @merge_request.check_if_can_be_merged end render json: {state: @merge_request.human_state} + rescue Gitlab::SatelliteNotExistError + render json: {state: :no_satellite} end def automerge @@ -88,12 +90,12 @@ class MergeRequestsController < ProjectResourceController end def branch_from - @commit = project.commit(params[:ref]) + @commit = @repository.commit(params[:ref]) @commit = CommitDecorator.decorate(@commit) end def branch_to - @commit = project.commit(params[:ref]) + @commit = @repository.commit(params[:ref]) @commit = CommitDecorator.decorate(@commit) end diff --git a/app/controllers/project_resource_controller.rb b/app/controllers/project_resource_controller.rb index 81bc3a91bd1..ea78b3ff7c4 100644 --- a/app/controllers/project_resource_controller.rb +++ b/app/controllers/project_resource_controller.rb @@ -1,3 +1,4 @@ class ProjectResourceController < ApplicationController before_filter :project + before_filter :repository end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 17b0921ba6c..6f1180eaa6b 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -2,6 +2,7 @@ require Rails.root.join('lib', 'gitlab', 'graph', 'json_builder') class ProjectsController < ProjectResourceController skip_before_filter :project, only: [:new, :create] + skip_before_filter :repository, only: [:new, :create] # Authorize before_filter :authorize_read_project!, except: [:index, :new, :create] @@ -58,7 +59,7 @@ class ProjectsController < ProjectResourceController respond_to do |format| format.html do - unless @project.empty_repo? + if @project.repository && !@project.repository.empty? @last_push = current_user.recent_push(@project.id) render :show else @@ -102,11 +103,10 @@ class ProjectsController < ProjectResourceController def destroy return access_denied! unless can?(current_user, :remove_project, project) - # Disable the UsersProject update_repository call, otherwise it will be - # called once for every person removed from the project - UsersProject.skip_callback(:destroy, :after, :update_repository) + # Delete team first in order to prevent multiple gitolite calls + project.team.truncate + project.destroy - UsersProject.set_callback(:destroy, :after, :update_repository) respond_to do |format| format.html { redirect_to root_path } diff --git a/app/controllers/refs_controller.rb b/app/controllers/refs_controller.rb index b48d5ec7027..09d9eb51b82 100644 --- a/app/controllers/refs_controller.rb +++ b/app/controllers/refs_controller.rb @@ -12,7 +12,7 @@ class RefsController < ProjectResourceController respond_to do |format| format.html do new_path = if params[:destination] == "tree" - project_tree_path(@project, @ref) + project_tree_path(@project, (@ref + "/" + params[:path])) else project_commits_path(@project, @ref) end @@ -31,7 +31,7 @@ class RefsController < ProjectResourceController contents = @tree.contents @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 + last_commit = @repo.commits(@commit.id, file, 1).last last_commit = CommitDecorator.decorate(last_commit) { file_name: content.name, @@ -45,10 +45,10 @@ class RefsController < ProjectResourceController def define_tree_vars params[:path] = nil if params[:path].blank? - @repo = project.repo - @commit = project.commit(@ref) + @repo = project.repository + @commit = @repo.commit(@ref) @commit = CommitDecorator.decorate(@commit) - @tree = Tree.new(@commit.tree, project, @ref, params[:path]) + @tree = Tree.new(@commit.tree, @ref, params[:path]) @tree = TreeDecorator.new(@tree) @hex_path = Digest::SHA1.hexdigest(params[:path] || "") diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 7678fbff3f1..229cb36949b 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -5,19 +5,19 @@ class RepositoriesController < ProjectResourceController before_filter :require_non_empty_project def show - @activities = @project.commits_with_refs(20) + @activities = @repository.commits_with_refs(20) end def branches - @branches = @project.branches + @branches = @repository.branches end def tags - @tags = @project.tags + @tags = @repository.tags end def stats - @stats = Gitlab::GitStats.new(@project.repo, @project.root_ref) + @stats = Gitlab::GitStats.new(@repository.raw, @repository.root_ref) @graph = @stats.graph end @@ -27,7 +27,7 @@ class RepositoriesController < ProjectResourceController end - file_path = @project.archive_repo(params[:ref]) + file_path = @repository.archive_repo(params[:ref]) if file_path # Send file to user diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 4f45f9ddccb..a23292396a0 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -1,6 +1,6 @@ class SearchController < ApplicationController def show - result = SearchContext.new(current_user.project_ids, params).execute + result = SearchContext.new(current_user.authorized_projects.map(&:id), params).execute @projects = result[:projects] @merge_requests = result[:merge_requests] diff --git a/app/controllers/services_controller.rb b/app/controllers/services_controller.rb index 50f7e97af9f..d0df469b967 100644 --- a/app/controllers/services_controller.rb +++ b/app/controllers/services_controller.rb @@ -26,7 +26,7 @@ class ServicesController < ProjectResourceController end def test - commits = project.commits(project.default_branch, nil, 3) + commits = project.repository.commits(project.default_branch, nil, 3) data = project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", current_user) @service = project.gitlab_ci_service diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb index 977524a4db8..26898abfa82 100644 --- a/app/controllers/snippets_controller.rb +++ b/app/controllers/snippets_controller.rb @@ -16,7 +16,7 @@ class SnippetsController < ProjectResourceController respond_to :html def index - @snippets = @project.snippets.fresh + @snippets = @project.snippets.fresh.non_expired end def new diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb index 311af62b8db..8378a8458ff 100644 --- a/app/controllers/team_members_controller.rb +++ b/app/controllers/team_members_controller.rb @@ -16,10 +16,9 @@ class TeamMembersController < ProjectResourceController end def create - @project.add_users_ids_to_team( - params[:user_ids], - params[:project_access] - ) + users = User.where(id: params[:user_ids]) + + @project.team << [users, params[:project_access]] if params[:redirect_to] redirect_to params[:redirect_to] @@ -50,7 +49,7 @@ class TeamMembersController < ProjectResourceController def apply_import giver = Project.find(params[:source_project_id]) - status = UsersProject.import_team(giver, project) + status = @project.team.import(giver) notice = status ? "Succesfully imported" : "Import failed" redirect_to project_team_members_path(project), notice: notice diff --git a/app/controllers/tree_controller.rb b/app/controllers/tree_controller.rb index 725f48fa014..2151bd7cbbd 100644 --- a/app/controllers/tree_controller.rb +++ b/app/controllers/tree_controller.rb @@ -22,7 +22,7 @@ class TreeController < ProjectResourceController end def edit - @last_commit = @project.last_commit_for(@ref, @path).sha + @last_commit = @project.repository.last_commit_for(@ref, @path).sha end def update diff --git a/app/decorators/tree_decorator.rb b/app/decorators/tree_decorator.rb index c12227afb5d..0e760f97dee 100644 --- a/app/decorators/tree_decorator.rb +++ b/app/decorators/tree_decorator.rb @@ -6,16 +6,14 @@ class TreeDecorator < ApplicationDecorator part_path = "" parts = path.split("\/") - #parts = parts[0...-1] if is_blob? - - yield(h.link_to("..", "#")) if parts.count > max_links + yield('..', nil) 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.project_tree_path(project, h.tree_join(ref, part_path)))) + yield(part, h.tree_join(ref, part_path)) end end end @@ -26,7 +24,7 @@ class TreeDecorator < ApplicationDecorator def up_dir_path file = File.join(path, "..") - h.project_tree_path(project, h.tree_join(ref, file)) + h.tree_join(ref, file) end def readme diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 52715a265bd..a1eea96be43 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -53,7 +53,7 @@ module ApplicationHelper def last_commit(project) if project.repo_exists? - time_ago_in_words(project.commit.committed_date) + " ago" + time_ago_in_words(project.repository.commit.committed_date) + " ago" else "Never" end @@ -62,9 +62,11 @@ module ApplicationHelper end def grouped_options_refs(destination = :tree) + repository = @project.repository + options = [ - ["Branch", @project.branch_names ], - [ "Tag", @project.tag_names ] + ["Branch", repository.branch_names ], + [ "Tag", repository.tag_names ] ] # If reference is commit id - @@ -78,7 +80,8 @@ module ApplicationHelper end def search_autocomplete_source - projects = current_user.projects.map{ |p| { label: p.name_with_namespace, url: project_path(p) } } + projects = current_user.authorized_projects.map { |p| { label: p.name_with_namespace, url: project_path(p) } } + groups = current_user.authorized_groups.map { |group| { label: "<group> #{group.name}", url: group_path(group) } } default_nav = [ { label: "My Profile", url: profile_path }, @@ -99,21 +102,21 @@ module ApplicationHelper ] project_nav = [] - if @project && !@project.new_record? + if @project && @project.repository && @project.repository.root_ref project_nav = [ { label: "#{@project.name} Issues", url: project_issues_path(@project) }, - { label: "#{@project.name} Commits", url: project_commits_path(@project, @ref || @project.root_ref) }, + { label: "#{@project.name} Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) }, { label: "#{@project.name} Merge Requests", url: project_merge_requests_path(@project) }, { label: "#{@project.name} Milestones", url: project_milestones_path(@project) }, { label: "#{@project.name} Snippets", url: project_snippets_path(@project) }, { label: "#{@project.name} Team", url: project_team_index_path(@project) }, - { label: "#{@project.name} Tree", url: project_tree_path(@project, @ref || @project.root_ref) }, + { label: "#{@project.name} Tree", url: project_tree_path(@project, @ref || @project.repository.root_ref) }, { label: "#{@project.name} Wall", url: wall_project_path(@project) }, { label: "#{@project.name} Wiki", url: project_wikis_path(@project) }, ] end - [projects, default_nav, project_nav, help_nav].flatten.to_json + [groups, projects, default_nav, project_nav, help_nav].flatten.to_json end def emoji_autocomplete_source @@ -139,6 +142,7 @@ module ApplicationHelper event.last_push_to_non_root? && !event.rm_ref? && event.project && + event.project.repository && event.project.merge_requests_enabled end diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 2349888ed7a..8fc637a2bf6 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -70,4 +70,12 @@ module CommitsHelper escape_javascript(render 'commits/commit', commit: commit) end end + + def diff_line_content(line) + if line.blank? + " " + else + line + end + end end diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index a2548a23e5e..9b9d2a913e9 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -20,25 +20,8 @@ module EventsHelper [event.action_name, target].join(" ") end - def event_image event - event_image_path = if event.push? - "event_push.png" - elsif event.merged? - "event_mr_merged.png" - end - - return nil unless event_image_path - - content_tag :div, class: 'event_icon' do - image_tag event_image_path - end - end - def event_filter_link key, tooltip key = key.to_s - - filter = @event_filter.options key - inactive = if @event_filter.active? key nil else @@ -46,7 +29,7 @@ module EventsHelper end content_tag :div, class: "filter_icon #{inactive}" do - link_to dashboard_path(event_filter: filter), class: 'has_tooltip', 'data-original-title' => tooltip do + link_to dashboard_path, class: 'has_tooltip event_filter_link', id: "#{key}_event_filter", 'data-original-title' => tooltip do image_tag "event_filter_#{key}.png" end end diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb new file mode 100644 index 00000000000..283119bc24c --- /dev/null +++ b/app/helpers/groups_helper.rb @@ -0,0 +1,17 @@ +module GroupsHelper + def group_filter_path(entity, options={}) + exist_opts = { + status: params[:status], + project_id: params[:project_id], + } + + options = exist_opts.merge(options) + + case entity + when 'issue' then + issues_group_path(@group, options) + when 'merge_request' + merge_requests_group_path(@group, options) + end + end +end diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index f48425bd6de..ca0a89c3749 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -4,7 +4,7 @@ module MergeRequestsHelper event.project, merge_request: { source_branch: event.branch_name, - target_branch: event.project.root_ref, + target_branch: event.project.repository.root_ref, title: event.branch_name.titleize } ) diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb index fdf6725cc13..2d25c8f854d 100644 --- a/app/helpers/namespaces_helper.rb +++ b/app/helpers/namespaces_helper.rb @@ -1,6 +1,6 @@ module NamespacesHelper def namespaces_options(selected = :current_user, scope = :default) - groups = current_user.namespaces.select {|n| n.type == 'Group'} + groups = current_user.owned_groups.select {|n| n.type == 'Group'} users = if scope == :all Namespace.root diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index 7d68e50b382..706d7a8e4ed 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -1,11 +1,12 @@ class Notify < ActionMailer::Base - include Resque::Mailer + add_template_helper ApplicationHelper add_template_helper GitlabMarkdownHelper default_url_options[:host] = Gitlab.config.gitlab.host default_url_options[:protocol] = Gitlab.config.gitlab.protocol default_url_options[:port] = Gitlab.config.gitlab.port if Gitlab.config.gitlab_on_non_standard_port? + default_url_options[:script_name] = Gitlab.config.gitlab.relative_url_root default from: Gitlab.config.gitlab.email_from @@ -87,7 +88,7 @@ class Notify < ActionMailer::Base def note_wall_email(recipient_id, note_id) @note = Note.find(note_id) @project = @note.project - mail(to: recipient(recipient_id), subject: subject) + mail(to: recipient(recipient_id), subject: subject("note on wall")) end @@ -147,12 +148,15 @@ class Notify < ActionMailer::Base # >> @project = Project.last # => #<Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...> # >> subject('Lorem ipsum') - # => "GitLab | Lorem ipsum | Ruby on Rails" + # => "GitLab | Ruby on Rails | Lorem ipsum " # # # Accepts multiple arguments # >> subject('Lorem ipsum', 'Dolor sit amet') # => "GitLab | Lorem ipsum | Dolor sit amet" def subject(*extra) - "GitLab | " << extra.join(' | ') << (@project ? " | #{@project.name}" : "") + subject = "GitLab" + subject << (@project ? " | #{@project.name_with_namespace}" : "") + subject << " | " + extra.join(' | ') if extra.present? + subject end end diff --git a/app/models/ability.rb b/app/models/ability.rb index 2d80c6720b7..256af1e800b 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -15,35 +15,26 @@ class Ability def project_abilities(user, project) rules = [] + team = project.team + # Rules based on role in project - if project.master_access_for?(user) + if team.masters.include?(user) rules << project_master_rules - elsif project.dev_access_for?(user) + elsif team.developers.include?(user) rules << project_dev_rules - elsif project.report_access_for?(user) + elsif team.reporters.include?(user) rules << project_report_rules - elsif project.guest_access_for?(user) + elsif team.guests.include?(user) rules << project_guest_rules end - if project.namespace - # If user own project namespace - # (Ex. group owner or account owner) - if project.namespace.owner == user - rules << project_admin_rules - end - else - # For compatibility with global projects - # use projects.owner_id - if project.owner == user - rules << project_admin_rules - end + if project.owner == user + rules << project_admin_rules end - rules.flatten end @@ -107,9 +98,12 @@ class Ability def group_abilities user, group rules = [] - rules << [ - :manage_group - ] if group.owner == user + # Only group owner and administrators can manage group + if group.owner == user || user.admin? + rules << [ + :manage_group + ] + end rules.flatten end diff --git a/app/models/commit.rb b/app/models/commit.rb index f11b7fe0202..17d41f27f34 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -11,7 +11,7 @@ class Commit attr_accessor :commit, :head, :refs delegate :message, :authored_date, :committed_date, :parents, :sha, - :date, :committer, :author, :message, :diffs, :tree, :id, + :date, :committer, :author, :diffs, :tree, :id, :stats, :to_patch, to: :commit class << self @@ -83,8 +83,8 @@ class Commit return result unless from && to - first = project.commit(to.try(:strip)) - last = project.commit(from.try(:strip)) + first = project.repository.commit(to.try(:strip)) + last = project.repository.commit(from.try(:strip)) if first && last result[:same] = (first.id == last.id) @@ -98,6 +98,8 @@ class Commit end def initialize(raw_commit, head = nil) + raise "Nil as raw commit passed" unless raw_commit + @commit = raw_commit @head = head end @@ -136,17 +138,17 @@ class Commit end def prev_commit - parents.try :first + @prev_commit ||= if parents.present? + Commit.new(parents.first) + else + nil + end end def prev_commit_id prev_commit.try :id end - def parents_count - parents && parents.count || 0 - end - # Shows the diff between the commit's parent and the commit. # # Cuts out the header and stats from #to_patch and returns only the diff. diff --git a/app/roles/issue_commonality.rb b/app/models/concerns/issuable.rb index 79831cdca67..d1717d3bbee 100644 --- a/app/roles/issue_commonality.rb +++ b/app/models/concerns/issuable.rb @@ -1,5 +1,10 @@ +# == Issuable concern +# # Contains common functionality shared between Issues and MergeRequests -module IssueCommonality +# +# Used by Issue, MergeRequest +# +module Issuable extend ActiveSupport::Concern included do @@ -64,4 +69,38 @@ module IssueCommonality closed_changed? && !closed end + # + # Votes + # + + # Return the number of -1 comments (downvotes) + def downvotes + notes.select(&:downvote?).size + end + + def downvotes_in_percent + if votes_count.zero? + 0 + else + 100.0 - upvotes_in_percent + end + end + + # Return the number of +1 comments (upvotes) + def upvotes + notes.select(&:upvote?).size + end + + def upvotes_in_percent + if votes_count.zero? + 0 + else + 100.0 / votes_count * upvotes + end + end + + # Return the total number of votes + def votes_count + upvotes + downvotes + end end diff --git a/app/models/event.rb b/app/models/event.rb index 90376e73753..d0ba61544d1 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -15,9 +15,6 @@ # class Event < ActiveRecord::Base - include NoteEvent - include PushEvent - attr_accessible :project, :action, :data, :author_id, :project_id, :target_id, :target_type @@ -113,26 +110,6 @@ class Event < ActiveRecord::Base target_type == "MergeRequest" end - def new_issue? - target_type == "Issue" && - action == Created - end - - def new_merge_request? - target_type == "MergeRequest" && - action == Created - end - - def changed_merge_request? - target_type == "MergeRequest" && - [Closed, Reopened].include?(action) - end - - def changed_issue? - target_type == "Issue" && - [Closed, Reopened].include?(action) - end - def joined? action == Joined end @@ -170,4 +147,143 @@ class Event < ActiveRecord::Base "opened" end end + + def valid_push? + data[:ref] + rescue => ex + false + end + + def tag? + data[:ref]["refs/tags"] + end + + def branch? + data[:ref]["refs/heads"] + end + + def new_branch? + commit_from =~ /^00000/ + end + + def new_ref? + commit_from =~ /^00000/ + end + + def rm_ref? + commit_to =~ /^00000/ + end + + def md_ref? + !(rm_ref? || new_ref?) + end + + def commit_from + data[:before] + end + + def commit_to + data[:after] + end + + def ref_name + if tag? + tag_name + else + branch_name + end + end + + def branch_name + @branch_name ||= data[:ref].gsub("refs/heads/", "") + end + + def tag_name + @tag_name ||= data[:ref].gsub("refs/tags/", "") + end + + # Max 20 commits from push DESC + def commits + @commits ||= data[:commits].map { |commit| repository.commit(commit[:id]) }.reverse + end + + def commits_count + data[:total_commits_count] || commits.count || 0 + end + + def ref_type + tag? ? "tag" : "branch" + end + + def push_action_name + if new_ref? + "pushed new" + elsif rm_ref? + "deleted" + else + "pushed to" + end + end + + def repository + project.repository + end + + def parent_commit + repository.commit(commit_from) + rescue => ex + nil + end + + def last_commit + repository.commit(commit_to) + rescue => ex + nil + end + + def push_with_commits? + md_ref? && commits.any? && parent_commit && last_commit + rescue Grit::NoSuchPathError + false + end + + def last_push_to_non_root? + branch? && project.default_branch != branch_name + end + + def note_commit_id + target.commit_id + end + + def note_short_commit_id + note_commit_id[0..8] + end + + def note_commit? + target.noteable_type == "Commit" + end + + def note_target + target.noteable + end + + def note_target_id + if note_commit? + target.commit_id + else + target.noteable_id.to_s + end + end + + def wall_note? + target.noteable_type.blank? + end + + def note_target_type + if target.noteable_type.present? + target.noteable_type.titleize + else + "Wall" + end.downcase + end end diff --git a/app/models/gitlab_ci_service.rb b/app/models/gitlab_ci_service.rb index a2f5634a86f..4eb39c7ef4d 100644 --- a/app/models/gitlab_ci_service.rb +++ b/app/models/gitlab_ci_service.rb @@ -23,20 +23,12 @@ class GitlabCiService < Service after_save :compose_service_hook, if: :activated? - def activated? - active - end - def compose_service_hook hook = service_hook || build_service_hook hook.url = [project_url, "/build", "?token=#{token}"].join("") hook.save end - def commit_badge_path sha - project_url + "/status?sha=#{sha}" - end - def commit_status_path sha project_url + "/builds/#{sha}/status.json?token=#{token}" end diff --git a/app/models/group.rb b/app/models/group.rb index b668f5560ab..8ba92980a9b 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -12,6 +12,14 @@ # class Group < Namespace + def add_users_to_project_teams(user_ids, project_access) + UsersProject.add_users_into_projects( + projects.map(&:id), + user_ids, + project_access + ) + end + def users users = User.joins(:users_projects).where(users_projects: {project_id: project_ids}) users = users << owner @@ -21,4 +29,8 @@ class Group < Namespace def human_name name end + + def truncate_teams + UsersProject.truncate_teams(project_ids) + end end diff --git a/app/models/issue.rb b/app/models/issue.rb index 1de9d0f9ebc..7381136c979 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -17,8 +17,7 @@ # class Issue < ActiveRecord::Base - include IssueCommonality - include Votes + include Issuable attr_accessible :title, :assignee_id, :closed, :position, :description, :milestone_id, :label_list, :author_id_of_changes diff --git a/app/models/key.rb b/app/models/key.rb index 5dac1c1c9fd..2bf50f56565 100644 --- a/app/models/key.rb +++ b/app/models/key.rb @@ -73,7 +73,7 @@ class Key < ActiveRecord::Base if is_deploy_key [project] else - user.projects + user.authorized_projects end end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 052e0850d96..b6ea85f6507 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -20,11 +20,10 @@ # require Rails.root.join("app/models/commit") -require Rails.root.join("app/roles/static_model") +require Rails.root.join("lib/static_model") class MergeRequest < ActiveRecord::Base - include IssueCommonality - include Votes + include Issuable attr_accessible :title, :assignee_id, :closed, :target_branch, :source_branch, :milestone_id, :author_id_of_changes diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 4fac9bec259..8b4c895dc17 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -29,7 +29,7 @@ class Milestone < ActiveRecord::Base def expired? if due_date - due_date < Date.today + due_date.past? else false end @@ -58,7 +58,13 @@ class Milestone < ActiveRecord::Base end def expires_at - "expires at #{due_date.stamp("Aug 21, 2011")}" if due_date + if due_date + if due_date.past? + "expired at #{due_date.stamp("Aug 21, 2011")}" + else + "expires at #{due_date.stamp("Aug 21, 2011")}" + end + end end def can_be_closed? diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 8c90f5aee26..89c1f9adb5a 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -27,10 +27,13 @@ class Namespace < ActiveRecord::Base after_create :ensure_dir_exist after_update :move_dir + after_commit :update_gitolite, on: :update, if: :require_update_gitolite after_destroy :rm_dir scope :root, where('type IS NULL') + attr_accessor :require_update_gitolite + def self.search query where("name LIKE :query OR path LIKE :query", query: "%#{query}%") end @@ -48,8 +51,17 @@ class Namespace < ActiveRecord::Base end def ensure_dir_exist - namespace_dir_path = File.join(Gitlab.config.gitolite.repos_path, path) - system("mkdir -m 770 #{namespace_dir_path}") unless File.exists?(namespace_dir_path) + unless dir_exists? + FileUtils.mkdir( namespace_full_path, mode: 0770 ) + end + end + + def dir_exists? + File.exists?(namespace_full_path) + end + + def namespace_full_path + @namespace_full_path ||= File.join(Gitlab.config.gitolite.repos_path, path) end def move_dir @@ -59,16 +71,25 @@ class Namespace < ActiveRecord::Base if File.exists?(new_path) raise "Already exists" end - - if system("mv #{old_path} #{new_path}") + + begin + FileUtils.mv( old_path, new_path ) send_update_instructions + @require_update_gitolite = true + rescue Exception => e + raise "Namespace move error #{old_path} #{new_path}" end end end + def update_gitolite + @require_update_gitolite = false + projects.each(&:update_repository) + end + def rm_dir dir_path = File.join(Gitlab.config.gitolite.repos_path, path) - system("rm -rf #{dir_path}") + FileUtils.rm_r( dir_path, force: true ) end def send_update_instructions diff --git a/app/models/note.rb b/app/models/note.rb index b62b3fe61d5..3ad03cc601b 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -4,7 +4,6 @@ # # id :integer not null, primary key # note :text -# noteable_id :string(255) # noteable_type :string(255) # author_id :integer # created_at :datetime not null @@ -12,6 +11,8 @@ # project_id :integer # attachment :string(255) # line_code :string(255) +# commit_id :string(255) +# noteable_id :integer # require 'carrierwave/orm/activerecord' @@ -41,11 +42,11 @@ class Note < ActiveRecord::Base mount_uploader :attachment, AttachmentUploader # Scopes - scope :for_commits, ->{ where(noteable_type: "Commit") } - scope :common, ->{ where(noteable_id: nil, commit_id: nil) } - scope :today, ->{ where("created_at >= :date", date: Date.today) } - scope :last_week, ->{ where("created_at >= :date", date: (Date.today - 7.days)) } - scope :since, ->(day) { where("created_at >= :date", date: (day)) } + scope :for_commit_id, ->(commit_id) { where(noteable_type: "Commit", commit_id: commit_id) } + scope :inline, where("line_code IS NOT NULL") + scope :not_inline, where("line_code IS NULL") + + scope :common, ->{ where(noteable_type: ["", nil]) } scope :fresh, ->{ order("created_at ASC, id ASC") } scope :inc_author_project, ->{ includes(:project, :author) } scope :inc_author, ->{ includes(:author) } @@ -126,7 +127,7 @@ class Note < ActiveRecord::Base # override to return commits, which are not active record def noteable if for_commit? - project.commit(commit_id) + project.repository.commit(commit_id) else super end diff --git a/app/models/project.rb b/app/models/project.rb index 251f497548e..32b951349a9 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -9,7 +9,7 @@ # created_at :datetime not null # updated_at :datetime not null # private_flag :boolean default(TRUE), not null -# owner_id :integer +# creator_id :integer # default_branch :string(255) # issues_enabled :boolean default(TRUE), not null # wall_enabled :boolean default(TRUE), not null @@ -21,18 +21,14 @@ require "grit" class Project < ActiveRecord::Base - include Repository - include PushObserver - include Authority - include Team - include NamespacedProject + include Gitolited class TransferError < StandardError; end attr_accessible :name, :path, :description, :default_branch, :issues_enabled, :wall_enabled, :merge_requests_enabled, :wiki_enabled, as: [:default, :admin] - attr_accessible :namespace_id, :owner_id, as: :admin + attr_accessible :namespace_id, :creator_id, as: :admin attr_accessor :error_code @@ -40,10 +36,10 @@ class Project < ActiveRecord::Base belongs_to :group, foreign_key: "namespace_id", conditions: "type = 'Group'" belongs_to :namespace - # TODO: replace owner with creator. - # With namespaces a project owner will be a namespace owner - # so this field makes sense only for global projects - belongs_to :owner, class_name: "User" + belongs_to :creator, + class_name: "User", + foreign_key: "creator_id" + has_many :users, through: :users_projects has_many :events, dependent: :destroy has_many :merge_requests, dependent: :destroy @@ -62,9 +58,11 @@ class Project < ActiveRecord::Base delegate :name, to: :owner, allow_nil: true, prefix: true # Validations - validates :owner, presence: true + validates :creator, presence: true validates :description, length: { within: 0..2000 } - validates :name, presence: true, length: { within: 0..255 } + validates :name, presence: true, length: { within: 0..255 }, + format: { with: Gitlab::Regex.project_name_regex, + message: "only letters, digits, spaces & '_' '-' '.' allowed. Letter should be first" } validates :path, presence: true, length: { within: 0..255 }, format: { with: Gitlab::Regex.path_regex, message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } @@ -77,19 +75,14 @@ class Project < ActiveRecord::Base validate :check_limit, :repo_name # Scopes - scope :public_only, where(private_flag: false) - scope :without_user, ->(user) { where("id NOT IN (:ids)", ids: user.projects.map(&:id) ) } + scope :without_user, ->(user) { where("id NOT IN (:ids)", ids: user.authorized_projects.map(&:id) ) } scope :not_in_group, ->(group) { where("id NOT IN (:ids)", ids: group.project_ids ) } + scope :in_namespace, ->(namespace) { where(namespace_id: namespace.id) } scope :sorted_by_activity, ->() { order("(SELECT max(events.created_at) FROM events WHERE events.project_id = projects.id) DESC") } scope :personal, ->(user) { where(namespace_id: user.namespace_id) } scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) } class << self - def authorized_for user - projects = includes(:users_projects, :namespace) - projects = projects.where("users_projects.user_id = :user_id or projects.owner_id = :user_id or namespaces.owner_id = :user_id", user_id: user.id) - end - def active joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC") end @@ -101,8 +94,10 @@ class Project < ActiveRecord::Base def find_with_namespace(id) if id.include?("/") id = id.split("/") - namespace_id = Namespace.find_by_path(id.first).id - where(namespace_id: namespace_id).find_by_path(id.last) + namespace = Namespace.find_by_path(id.first) + return nil unless namespace + + where(namespace_id: namespace.id).find_by_path(id.second) else where(path: id, namespace_id: nil).last end @@ -122,7 +117,7 @@ class Project < ActiveRecord::Base # project.path = project.name.dup.parameterize - project.owner = user + project.creator = user # Apply namespace if user has access to it # else fallback to user namespace @@ -162,6 +157,20 @@ class Project < ActiveRecord::Base end end + def team + @team ||= Team.new(self) + end + + def repository + if path + @repository ||= Repository.new(path_with_namespace, default_branch) + else + nil + end + rescue Grit::NoSuchPathError + nil + end + def git_error? error_code == :gitolite end @@ -171,8 +180,8 @@ class Project < ActiveRecord::Base end def check_limit - unless owner.can_create_project? - errors[:base] << ("Your own projects limit is #{owner.projects_limit}! Please contact administrator to increase it") + unless creator.can_create_project? + errors[:base] << ("Your own projects limit is #{creator.projects_limit}! Please contact administrator to increase it") end rescue errors[:base] << ("Can't check your ability to create project") @@ -198,30 +207,10 @@ class Project < ActiveRecord::Base [Gitlab.config.gitlab.url, path_with_namespace].join("/") end - def common_notes - notes.where(noteable_type: ["", nil]).inc_author_project - end - def build_commit_note(commit) notes.new(commit_id: commit.id, noteable_type: "Commit") end - def commit_notes(commit) - notes.where(commit_id: commit.id, noteable_type: "Commit").where('line_code IS NULL OR line_code = ""') - end - - def commit_line_notes(commit) - notes.where(commit_id: commit.id, noteable_type: "Commit").where("line_code IS NOT NULL") - end - - def public? - !private_flag - end - - def private? - private_flag - end - def last_activity last_event end @@ -262,7 +251,282 @@ class Project < ActiveRecord::Base def send_move_instructions self.users_projects.each do |member| - Notify.project_was_moved_email(member.id).deliver + Notify.delay.project_was_moved_email(member.id) + end + end + + def owner + if namespace + namespace_owner + else + creator + end + end + + def team_member_by_name_or_email(name = nil, email = nil) + user = users.where("name like ? or email like ?", name, email).first + users_projects.where(user: user) 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 + + def transfer(new_namespace) + Project.transaction do + old_namespace = namespace + self.namespace = new_namespace + + old_dir = old_namespace.try(:path) || '' + new_dir = new_namespace.try(:path) || '' + + old_repo = if old_dir.present? + File.join(old_dir, self.path) + else + self.path + end + + if Project.where(path: self.path, namespace_id: new_namespace.try(:id)).present? + raise TransferError.new("Project with same path in target namespace already exists") + end + + Gitlab::ProjectMover.new(self, old_dir, new_dir).execute + + gitolite.move_repository(old_repo, self) + + save! + end + rescue Gitlab::ProjectMover::ProjectMoveError => ex + raise Project::TransferError.new(ex.message) + end + + def name_with_namespace + @name_with_namespace ||= begin + if namespace + namespace.human_name + " / " + name + else + name + end + end + end + + def namespace_owner + namespace.try(:owner) + end + + def path_with_namespace + if namespace + namespace.path + '/' + path + else + path + end + end + + # This method will be called after each post receive and only if the provided + # user is present in GitLab. + # + # All callbacks for post receive should be placed here. + def trigger_post_receive(oldrev, newrev, ref, user) + data = post_receive_data(oldrev, newrev, ref, user) + + # Create push event + self.observe_push(data) + + if push_to_branch? ref, oldrev + # Close merged MR + self.update_merge_requests(oldrev, newrev, ref, user) + + # Execute web hooks + self.execute_hooks(data.dup) + + # Execute project services + self.execute_services(data.dup) + end + + # Create satellite + self.satellite.create unless self.satellite.exists? + + # Discover the default branch, but only if it hasn't already been set to + # something else + if repository && default_branch.nil? + update_attributes(default_branch: self.repository.discover_default_branch) + end + end + + def push_to_branch? ref, oldrev + ref_parts = ref.split('/') + + # Return if this is not a push to a branch (e.g. new commits) + !(ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000") + end + + def observe_push(data) + Event.create( + project: self, + action: Event::Pushed, + data: data, + author_id: data[:user_id] + ) + end + + def execute_hooks(data) + hooks.each { |hook| hook.execute(data) } + end + + def execute_services(data) + services.each do |service| + + # Call service hook only if it is active + service.execute(data) if service.active + end + end + + # Produce a hash of post-receive data + # + # data = { + # before: String, + # after: String, + # ref: String, + # user_id: String, + # user_name: String, + # repository: { + # name: String, + # url: String, + # description: String, + # homepage: String, + # }, + # commits: Array, + # total_commits_count: Fixnum + # } + # + def post_receive_data(oldrev, newrev, ref, user) + + push_commits = repository.commits_between(oldrev, newrev) + + # Total commits count + push_commits_count = push_commits.size + + # Get latest 20 commits ASC + push_commits_limited = push_commits.last(20) + + # Hash to be passed as post_receive_data + data = { + before: oldrev, + after: newrev, + ref: ref, + user_id: user.id, + user_name: user.name, + repository: { + name: name, + url: url_to_repo, + description: description, + homepage: web_url, + }, + commits: [], + total_commits_count: push_commits_count + } + + # For perfomance purposes maximum 20 latest commits + # will be passed as post receive hook data. + # + push_commits_limited.each do |commit| + data[:commits] << { + id: commit.id, + message: commit.safe_message, + timestamp: commit.date.xmlschema, + url: "#{Gitlab.config.gitlab.url}/#{path_with_namespace}/commit/#{commit.id}", + author: { + name: commit.author_name, + email: commit.author_email + } + } end + + data + end + + def update_merge_requests(oldrev, newrev, ref, user) + return true unless ref =~ /heads/ + branch_name = ref.gsub("refs/heads/", "") + c_ids = self.repository.commits_between(oldrev, newrev).map(&:id) + + # Update code for merge requests + mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all + 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 = 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 valid_repo? + repo + rescue + errors.add(:path, "Invalid repository path") + false + end + + def empty_repo? + !repository || repository.empty? + end + + def satellite + @satellite ||= Gitlab::Satellite::Satellite.new(self) + end + + def repo + repository.raw + end + + def url_to_repo + gitolite.url_to_repo(path_with_namespace) + end + + def namespace_dir + namespace.try(:path) || '' + end + + def update_repository + gitolite.update_repository(self) + end + + def destroy_repository + gitolite.remove_repository(self) + end + + def repo_exists? + @repo_exists ||= (repository && repository.branches.present?) + rescue + @repo_exists = false + end + + def open_branches + if protected_branches.empty? + self.repo.heads + else + pnames = protected_branches.map(&:name) + self.repo.heads.reject { |h| pnames.include?(h.name) } + end.sort_by(&:name) + end + + def root_ref?(branch) + repository.root_ref == branch + end + + def ssh_url_to_repo + url_to_repo + end + + def http_url_to_repo + http_url = [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('') + end + + # Check if current branch name is marked as protected in the system + def protected_branch? branch_name + protected_branches.map(&:name).include?(branch_name) end end diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb index c54aa3ce9a2..3308caf360a 100644 --- a/app/models/protected_branch.rb +++ b/app/models/protected_branch.rb @@ -10,7 +10,7 @@ # class ProtectedBranch < ActiveRecord::Base - include GitHost + include Gitolited attr_accessible :name @@ -22,10 +22,10 @@ class ProtectedBranch < ActiveRecord::Base after_destroy :update_repository def update_repository - git_host.update_repository(project) + gitolite.update_repository(project) end def commit - project.commit(self.name) + project.repository.commit(self.name) end end diff --git a/app/roles/repository.rb b/app/models/repository.rb index 78190ca96d0..cf8ba4530a1 100644 --- a/app/roles/repository.rb +++ b/app/models/repository.rb @@ -1,15 +1,35 @@ -module Repository - include GitHost +class Repository + # Repository directory name with namespace direcotry + # Examples: + # gitlab/gitolite + # diaspora + # + attr_accessor :path_with_namespace + + # Grit repo object + attr_accessor :repo + + # Default branch in the repository + attr_accessor :root_ref + + def initialize(path_with_namespace, root_ref = 'master') + @root_ref = root_ref || "master" + @path_with_namespace = path_with_namespace - def valid_repo? + # Init grit repo object + repo + end + + def raw repo - rescue - errors.add(:path, "Invalid repository path") - false end - def empty_repo? - !repo_exists? || !has_commits? + def path_to_repo + @path_to_repo ||= File.join(Gitlab.config.gitolite.repos_path, "#{path_with_namespace}.git") + end + + def repo + @repo ||= Grit::Repo.new(path_to_repo) end def commit(commit_id = nil) @@ -40,10 +60,6 @@ module Repository Commit.commits_between(repo, from, to) end - def satellite - @satellite ||= Gitlab::Satellite::Satellite.new(self) - end - def has_post_receive_file? !!hook_file end @@ -88,36 +104,6 @@ module Repository [branch_names + tag_names].flatten end - def repo - @repo ||= Grit::Repo.new(path_to_repo) - end - - def url_to_repo - git_host.url_to_repo(path_with_namespace) - end - - def path_to_repo - File.join(Gitlab.config.gitolite.repos_path, "#{path_with_namespace}.git") - end - - def namespace_dir - namespace.try(:path) || '' - end - - def update_repository - git_host.update_repository(self) - end - - def destroy_repository - git_host.remove_repository(self) - end - - def repo_exists? - @repo_exists ||= (repo && !repo.branches.empty?) - rescue - @repo_exists = false - end - def heads @heads ||= repo.heads end @@ -128,13 +114,14 @@ module Repository path ? (tree / path) : tree end - def open_branches - if protected_branches.empty? - self.repo.heads - else - pnames = protected_branches.map(&:name) - self.repo.heads.reject { |h| pnames.include?(h.name) } - end.sort_by(&:name) + def has_commits? + !!commit + rescue Grit::NoSuchPathError + false + end + + def empty? + !has_commits? end # Discovers the default branch based on the repository's available branches @@ -153,20 +140,6 @@ module Repository end end - def has_commits? - !!commit - rescue Grit::NoSuchPathError - false - end - - def root_ref - default_branch || "master" - end - - def root_ref?(branch) - root_ref == branch - end - # Archive Project to .tar.gz # # Already packed repo archives stored at @@ -193,17 +166,4 @@ module Repository file_path end - - def ssh_url_to_repo - url_to_repo - end - - def http_url_to_repo - http_url = [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('') - end - - # Check if current branch name is marked as protected in the system - def protected_branch? branch_name - protected_branches.map(&:name).include?(branch_name) - end end diff --git a/app/models/service.rb b/app/models/service.rb index 17a7a656de5..d3486d29200 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -20,4 +20,8 @@ class Service < ActiveRecord::Base has_one :service_hook validates :project_id, presence: true + + def activated? + active + end end diff --git a/app/models/system_hook.rb b/app/models/system_hook.rb index 2ae5b1314e9..5f1bd6477c4 100644 --- a/app/models/system_hook.rb +++ b/app/models/system_hook.rb @@ -19,6 +19,6 @@ class SystemHook < WebHook end def async_execute(data) - Resque.enqueue(SystemHookWorker, id, data) + Sidekiq::Client.enqueue(SystemHookWorker, id, data) end end diff --git a/app/models/team.rb b/app/models/team.rb new file mode 100644 index 00000000000..f235d20ebdb --- /dev/null +++ b/app/models/team.rb @@ -0,0 +1,118 @@ +class Team + attr_accessor :project + + def initialize(project) + @project = project + end + + # Shortcut to add users + # + # Use: + # @team << [@user, :master] + # @team << [@users, :master] + # + def << args + users = args.first + + if users.respond_to?(:each) + add_users(users, args.second) + else + add_user(users, args.second) + end + end + + def add_user(user, access) + add_users_ids([user.id], access) + end + + def add_users(users, access) + add_users_ids(users.map(&:id), access) + end + + def add_users_ids(user_ids, access) + UsersProject.add_users_into_projects( + [project.id], + user_ids, + access + ) + end + + # Remove all users from project team + def truncate + UsersProject.truncate_team(project) + end + + def members + project.users_projects + end + + def guests + members.guests.map(&:user) + end + + def reporters + members.reporters.map(&:user) + end + + def developers + members.developers.map(&:user) + end + + def masters + members.masters.map(&:user) + end + + def repository_readers + repository_members[UsersProject::REPORTER] + end + + def repository_writers + repository_members[UsersProject::DEVELOPER] + end + + def repository_masters + repository_members[UsersProject::MASTER] + end + + def repository_members + keys = Hash.new {|h,k| h[k] = [] } + UsersProject.select("keys.identifier, project_access"). + joins(user: :keys).where(project_id: project.id). + each {|row| keys[row.project_access] << [row.identifier] } + + keys[UsersProject::REPORTER] += project.deploy_keys.pluck(:identifier) + keys + end + + def import(source_project) + target_project = project + + source_team = source_project.users_projects.all + target_team = target_project.users_projects.all + target_user_ids = target_team.map(&:user_id) + + source_team.reject! do |tm| + # Skip if user already present in team + target_user_ids.include?(tm.user_id) + end + + source_team.map! do |tm| + new_tm = tm.dup + new_tm.id = nil + new_tm.project_id = target_project.id + new_tm.skip_git = true + new_tm + end + + UsersProject.transaction do + source_team.each do |tm| + tm.save + end + target_project.update_repository + end + + true + rescue + false + end +end diff --git a/app/models/tree.rb b/app/models/tree.rb index c3dfd4c718c..96395a42394 100644 --- a/app/models/tree.rb +++ b/app/models/tree.rb @@ -1,12 +1,13 @@ class Tree include Linguist::BlobHelper - attr_accessor :path, :tree, :project, :ref + + attr_accessor :path, :tree, :ref delegate :contents, :basename, :name, :data, :mime_type, :mode, :size, :text?, :colorize, to: :tree - def initialize(raw_tree, project, ref = nil, path = nil) - @project, @ref, @path = project, ref, path + def initialize(raw_tree, ref = nil, path = nil) + @ref, @path = ref, path @tree = if path.present? raw_tree / path else diff --git a/app/models/user.rb b/app/models/user.rb index 1bc070f040d..55d75892fc4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -34,8 +34,6 @@ # class User < ActiveRecord::Base - include Account - devise :database_authenticatable, :token_authenticatable, :lockable, :recoverable, :rememberable, :trackable, :validatable, :omniauthable @@ -51,7 +49,6 @@ class User < ActiveRecord::Base has_many :groups, class_name: "Group", foreign_key: :owner_id has_many :keys, dependent: :destroy - has_many :projects, through: :users_projects has_many :users_projects, dependent: :destroy has_many :issues, foreign_key: :author_id, dependent: :destroy has_many :notes, foreign_key: :author_id, dependent: :destroy @@ -70,6 +67,8 @@ class User < ActiveRecord::Base message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } + validate :namespace_uniq, if: ->(user) { user.username_changed? } + before_validation :generate_password, on: :create before_save :ensure_authentication_token alias_attribute :private_token, :authentication_token @@ -77,11 +76,14 @@ class User < ActiveRecord::Base delegate :path, to: :namespace, allow_nil: true, prefix: true # Scopes - scope :not_in_project, ->(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 :alphabetically, order('name ASC') + # + # Class methods + # class << self def filter filter_name case filter_name @@ -93,6 +95,14 @@ class User < ActiveRecord::Base end end + def not_in_project(project) + if project.users.present? + where("id not in (:ids)", ids: project.users.map(&:id) ) + else + scoped + end + end + def without_projects where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') end @@ -118,9 +128,158 @@ class User < ActiveRecord::Base end end + # + # Instance methods + # def generate_password if self.force_random_password self.password = self.password_confirmation = Devise.friendly_token.first(8) end end + + def namespace_uniq + namespace_name = self.username + if Namespace.find_by_path(namespace_name) + self.errors.add :username, "already exist" + end + end + + # Namespaces user has access to + def namespaces + namespaces = [] + + # Add user account namespace + namespaces << self.namespace if self.namespace + + # Add groups you can manage + namespaces += if admin + Group.all + else + groups.all + end + namespaces + end + + # Groups where user is an owner + def owned_groups + groups + end + + # Groups user has access to + def authorized_groups + @authorized_groups ||= begin + groups = Group.where(id: self.authorized_projects.pluck(:namespace_id)).all + groups = groups + self.groups + groups.uniq + end + end + + + # Projects user has access to + def authorized_projects + project_ids = users_projects.pluck(:project_id) + project_ids = project_ids | owned_projects.pluck(:id) + Project.where(id: project_ids) + end + + # Projects in user namespace + def personal_projects + Project.personal(self) + end + + # Projects where user is an owner + def owned_projects + Project.where("(projects.namespace_id IN (:namespaces)) OR + (projects.namespace_id IS NULL AND projects.creator_id = :user_id)", + namespaces: namespaces.map(&:id), user_id: self.id) + end + + # Team membership in personal projects + def tm_in_personal_projects + UsersProject.where(project_id: personal_projects.map(&:id), user_id: self.id) + end + + # Returns a string for use as a Gitolite user identifier + # + # Note that Gitolite 2.x requires the following pattern for users: + # + # ^@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$ + def identifier + # Replace non-word chars with underscores, then make sure it starts with + # valid chars + email.gsub(/\W/, '_').gsub(/\A([\W\_])+/, '') + end + + def is_admin? + admin + end + + def require_ssh_key? + keys.count == 0 + end + + def can_create_project? + projects_limit > personal_projects.count + end + + def can_create_group? + is_admin? + end + + def abilities + @abilities ||= begin + abilities = Six.new + abilities << Ability + abilities + end + end + + def can? action, subject + abilities.allowed?(self, action, subject) + end + + def first_name + name.split.first unless name.blank? + end + + def cared_merge_requests + MergeRequest.where("author_id = :id or assignee_id = :id", id: self.id) + end + + # Remove user from all projects and + # set blocked attribute to true + def block + users_projects.find_each do |membership| + return false unless membership.destroy + end + + self.blocked = true + save + end + + def projects_limit_percent + return 100 if projects_limit.zero? + (personal_projects.count.to_f / projects_limit) * 100 + end + + 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 + + # Take only latest one + events = events.recent.limit(1).first + end + + def projects_sorted_by_activity + authorized_projects.sorted_by_activity + end + + def several_namespaces? + namespaces.size > 1 + end + + def namespace_id + namespace.try :id + end end diff --git a/app/models/users_project.rb b/app/models/users_project.rb index 3d76a4df037..79146289836 100644 --- a/app/models/users_project.rb +++ b/app/models/users_project.rb @@ -11,7 +11,7 @@ # class UsersProject < ActiveRecord::Base - include GitHost + include Gitolited GUEST = 10 REPORTER = 20 @@ -23,87 +23,96 @@ class UsersProject < ActiveRecord::Base belongs_to :user belongs_to :project - after_save :update_repository - after_destroy :update_repository + attr_accessor :skip_git + + after_save :update_repository, unless: :skip_git? + after_destroy :update_repository, unless: :skip_git? validates :user, presence: true - validates :user_id, uniqueness: { :scope => [:project_id], message: "already exists in project" } + validates :user_id, uniqueness: { scope: [:project_id], message: "already exists in project" } validates :project_access, inclusion: { in: [GUEST, REPORTER, DEVELOPER, MASTER] }, presence: true validates :project, presence: true delegate :name, :email, to: :user, prefix: true + scope :guests, where(project_access: GUEST) + scope :reporters, where(project_access: REPORTER) + scope :developers, where(project_access: DEVELOPER) + scope :masters, where(project_access: MASTER) + scope :in_project, ->(project) { where(project_id: project.id) } + class << self - def import_team(source_project, target_project) - UsersProject.without_repository_callback do - UsersProject.transaction do - team = source_project.users_projects.all - - team.each do |tm| - # Skip if user already present in team - next if target_project.users.include?(tm.user) - - new_tm = tm.dup - new_tm.id = nil - new_tm.project_id = target_project.id - new_tm.save + + # Add users to project teams with passed access option + # + # access can be an integer representing a access code + # or symbol like :master representing role + # + # Ex. + # add_users_into_projects( + # project_ids, + # user_ids, + # UsersProject::MASTER + # ) + # + # add_users_into_projects( + # project_ids, + # user_ids, + # :master + # ) + # + def add_users_into_projects(project_ids, user_ids, access) + project_access = if roles_hash.has_key?(access) + roles_hash[access] + elsif roles_hash.values.include?(access.to_i) + access + else + raise "Non valid access" + end + + UsersProject.transaction do + project_ids.each do |project_id| + user_ids.each do |user_id| + users_project = UsersProject.new(project_access: project_access, user_id: user_id) + users_project.project_id = project_id + users_project.skip_git = true + users_project.save end end + Gitlab::Gitolite.new.update_repositories(Project.where(id: project_ids)) end - target_project.update_repository true rescue false end - def without_repository_callback - UsersProject.skip_callback(:destroy, :after, :update_repository) - yield - UsersProject.set_callback(:destroy, :after, :update_repository) - end - - def bulk_delete(project, user_ids) + def truncate_teams(project_ids) UsersProject.transaction do - UsersProject.where(:user_id => user_ids, :project_id => project.id).each do |users_project| + users_projects = UsersProject.where(project_id: project_ids) + users_projects.each do |users_project| + users_project.skip_git = true users_project.destroy end + Gitlab::Gitolite.new.update_repositories(Project.where(id: project_ids)) end - end - def bulk_update(project, user_ids, project_access) - UsersProject.transaction do - UsersProject.where(:user_id => user_ids, :project_id => project.id).each do |users_project| - users_project.project_access = project_access - users_project.save - end - end + true + rescue + false end - def 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 - ) - users_project.project = project - users_project.save - end - end + def truncate_team project + truncate_teams [project.id] end - def user_bulk_import(user, project_ids, project_access) - UsersProject.transaction do - project_ids.each do |project_id| - users_project = UsersProject.new( - project_access: project_access, - ) - users_project.project_id = project_id - users_project.user_id = user.id - users_project.save - end - end + def roles_hash + { + guest: GUEST, + reporter: REPORTER, + developer: DEVELOPER, + master: MASTER + } end def access_roles @@ -116,12 +125,8 @@ class UsersProject < ActiveRecord::Base end end - def role_access - project_access - end - def update_repository - git_host.update_repository(project) + gitolite.update_repository(project) end def project_access_human @@ -131,4 +136,8 @@ class UsersProject < ActiveRecord::Base def repo_access_human self.class.access_roles.invert[self.project_access] end + + def skip_git? + !!@skip_git + end end diff --git a/app/models/wiki.rb b/app/models/wiki.rb index 252a97e8cca..4f113957f99 100644 --- a/app/models/wiki.rb +++ b/app/models/wiki.rb @@ -50,5 +50,4 @@ class Wiki < ActiveRecord::Base def set_slug self.slug = self.title.parameterize end - end diff --git a/app/observers/issue_observer.rb b/app/observers/issue_observer.rb index 131336be8b6..262d0f892c4 100644 --- a/app/observers/issue_observer.rb +++ b/app/observers/issue_observer.rb @@ -3,7 +3,7 @@ class IssueObserver < ActiveRecord::Observer def after_create(issue) if issue.assignee && issue.assignee != current_user - Notify.new_issue_email(issue.id).deliver + Notify.delay.new_issue_email(issue.id) end end @@ -16,7 +16,7 @@ class IssueObserver < ActiveRecord::Observer if status Note.create_status_change_note(issue, current_user, status) [issue.author, issue.assignee].compact.each do |recipient| - Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user.id).deliver + Notify.delay.issue_status_changed_email(recipient.id, issue.id, status, current_user.id) end end end @@ -27,7 +27,7 @@ class IssueObserver < ActiveRecord::Observer recipient_ids = [issue.assignee_id, issue.assignee_id_was].keep_if {|id| id && id != current_user.id } recipient_ids.each do |recipient_id| - Notify.reassigned_issue_email(recipient_id, issue.id, issue.assignee_id_was).deliver + Notify.delay.reassigned_issue_email(recipient_id, issue.id, issue.assignee_id_was) end end end diff --git a/app/observers/key_observer.rb b/app/observers/key_observer.rb index a3f17bdec92..bf5fa647647 100644 --- a/app/observers/key_observer.rb +++ b/app/observers/key_observer.rb @@ -1,12 +1,12 @@ class KeyObserver < ActiveRecord::Observer - include GitHost + include Gitolited def after_save(key) - git_host.set_key(key.identifier, key.key, key.projects) + gitolite.set_key(key.identifier, key.key, key.projects) end def after_destroy(key) return if key.is_deploy_key && !key.last_deploy? - git_host.remove_key(key.identifier, key.projects) + gitolite.remove_key(key.identifier, key.projects) end end diff --git a/app/observers/merge_request_observer.rb b/app/observers/merge_request_observer.rb index c4040f1542d..6d3c2bdd186 100644 --- a/app/observers/merge_request_observer.rb +++ b/app/observers/merge_request_observer.rb @@ -3,7 +3,7 @@ class MergeRequestObserver < ActiveRecord::Observer def after_create(merge_request) if merge_request.assignee && merge_request.assignee != current_user - Notify.new_merge_request_email(merge_request.id).deliver + Notify.delay.new_merge_request_email(merge_request.id) end end @@ -25,7 +25,7 @@ class MergeRequestObserver < ActiveRecord::Observer recipients_ids.delete current_user.id recipients_ids.each do |recipient_id| - Notify.reassigned_merge_request_email(recipient_id, merge_request.id, merge_request.assignee_id_was).deliver + Notify.delay.reassigned_merge_request_email(recipient_id, merge_request.id, merge_request.assignee_id_was) end end end diff --git a/app/observers/note_observer.rb b/app/observers/note_observer.rb index 0a353cf1092..2ec644ef7c1 100644 --- a/app/observers/note_observer.rb +++ b/app/observers/note_observer.rb @@ -11,7 +11,7 @@ class NoteObserver < ActiveRecord::Observer notify_team(note) elsif note.notify_author # Notify only author of resource - Notify.note_commit_email(note.noteable.author_email, note.id).deliver + Notify.delay.note_commit_email(note.noteable.author_email, note.id) else # Otherwise ignore it nil @@ -26,7 +26,7 @@ class NoteObserver < ActiveRecord::Observer if Notify.respond_to? notify_method team_without_note_author(note).map do |u| - Notify.send(notify_method, u.id, note.id).deliver + Notify.delay.send(notify_method, u.id, note.id) end end end diff --git a/app/observers/user_observer.rb b/app/observers/user_observer.rb index 09b3c1d622f..c1179ed7881 100644 --- a/app/observers/user_observer.rb +++ b/app/observers/user_observer.rb @@ -2,7 +2,7 @@ class UserObserver < ActiveRecord::Observer def after_create(user) log_info("User \"#{user.name}\" (#{user.email}) was created") - Notify.new_user_email(user.id, user.password).deliver + Notify.delay.new_user_email(user.id, user.password) end def after_destroy user @@ -14,7 +14,7 @@ class UserObserver < ActiveRecord::Observer if user.namespace user.namespace.update_attributes(path: user.username) else - user.create_namespace!(path: user.username, name: user.name) + user.create_namespace!(path: user.username, name: user.username) end end end diff --git a/app/observers/users_project_observer.rb b/app/observers/users_project_observer.rb index 0c9c2b2614a..b969d6a13ef 100644 --- a/app/observers/users_project_observer.rb +++ b/app/observers/users_project_observer.rb @@ -1,7 +1,7 @@ class UsersProjectObserver < ActiveRecord::Observer def after_commit(users_project) return if users_project.destroyed? - Notify.project_access_granted_email(users_project.id).deliver + Notify.delay.project_access_granted_email(users_project.id) end def after_create(users_project) diff --git a/app/roles/account.rb b/app/roles/account.rb deleted file mode 100644 index ede12b6056d..00000000000 --- a/app/roles/account.rb +++ /dev/null @@ -1,124 +0,0 @@ -module Account - # Returns a string for use as a Gitolite user identifier - # - # Note that Gitolite 2.x requires the following pattern for users: - # - # ^@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$ - def identifier - # Replace non-word chars with underscores, then make sure it starts with - # valid chars - email.gsub(/\W/, '_').gsub(/\A([\W\_])+/, '') - end - - def is_admin? - admin - end - - def require_ssh_key? - keys.count == 0 - end - - def can_create_project? - projects_limit > my_own_projects.count - end - - def can_create_group? - is_admin? - end - - def abilities - @abilities ||= begin - abilities = Six.new - abilities << Ability - abilities - end - end - - def can? action, subject - abilities.allowed?(self, action, subject) - end - - def last_activity_project - projects.first - end - - def first_name - name.split.first unless name.blank? - end - - def cared_merge_requests - MergeRequest.where("author_id = :id or assignee_id = :id", id: self.id) - end - - def project_ids - projects.map(&:id) - end - - # Remove user from all projects and - # set blocked attribute to true - def block - users_projects.find_each do |membership| - return false unless membership.destroy - end - - self.blocked = true - save - end - - def projects_limit_percent - return 100 if projects_limit.zero? - (my_own_projects.count.to_f / projects_limit) * 100 - end - - 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 - - # Take only latest one - events = events.recent.limit(1).first - end - - def projects_sorted_by_activity - projects.sorted_by_activity - end - - def namespaces - namespaces = [] - - # Add user account namespace - namespaces << self.namespace if self.namespace - - # Add groups you can manage - namespaces += if admin - Group.all - else - groups.all - end - namespaces - end - - def several_namespaces? - namespaces.size > 1 - end - - def namespace_id - namespace.try :id - end - - def authorized_groups - @authorized_groups ||= begin - groups = Group.where(id: self.projects.pluck(:namespace_id)).all - groups = groups + self.groups - groups.uniq - end - end - - def authorized_projects - Project.authorized_for(self) - end - - def my_own_projects - Project.personal(self) - end -end diff --git a/app/roles/authority.rb b/app/roles/authority.rb deleted file mode 100644 index e0796d5f120..00000000000 --- a/app/roles/authority.rb +++ /dev/null @@ -1,58 +0,0 @@ -module Authority - # Compatible with all access rights - # Should be rewrited for new access rights - def add_access(user, *access) - access = if access.include?(:admin) - { project_access: UsersProject::MASTER } - elsif access.include?(:write) - { project_access: UsersProject::DEVELOPER } - else - { project_access: UsersProject::REPORTER } - end - 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 - end - - def repository_readers - 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}). - 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}). - 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? - end - - def guest_access_for?(user) - !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? - end - - def dev_access_for?(user) - !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? - end -end diff --git a/app/roles/git_host.rb b/app/roles/git_host.rb deleted file mode 100644 index aa620f77ea4..00000000000 --- a/app/roles/git_host.rb +++ /dev/null @@ -1,5 +0,0 @@ -module GitHost - def git_host - Gitlab::Gitolite.new - end -end diff --git a/app/roles/namespaced_project.rb b/app/roles/namespaced_project.rb deleted file mode 100644 index 8656890a456..00000000000 --- a/app/roles/namespaced_project.rb +++ /dev/null @@ -1,59 +0,0 @@ -module NamespacedProject - def transfer(new_namespace) - Project.transaction do - old_namespace = namespace - self.namespace = new_namespace - - old_dir = old_namespace.try(:path) || '' - new_dir = new_namespace.try(:path) || '' - - old_repo = if old_dir.present? - File.join(old_dir, self.path) - else - self.path - end - - if Project.where(path: self.path, namespace_id: new_namespace.try(:id)).present? - raise TransferError.new("Project with same path in target namespace already exists") - end - - Gitlab::ProjectMover.new(self, old_dir, new_dir).execute - - git_host.move_repository(old_repo, self) - - save! - end - rescue Gitlab::ProjectMover::ProjectMoveError => ex - raise TransferError.new(ex.message) - end - - def name_with_namespace - @name_with_namespace ||= begin - if namespace - namespace.human_name + " / " + name - else - name - end - end - end - - def namespace_owner - namespace.try(:owner) - end - - def chief - if namespace - namespace_owner - else - owner - end - end - - def path_with_namespace - if namespace - namespace.path + '/' + path - else - path - end - end -end diff --git a/app/roles/note_event.rb b/app/roles/note_event.rb deleted file mode 100644 index db4ced0c095..00000000000 --- a/app/roles/note_event.rb +++ /dev/null @@ -1,37 +0,0 @@ -module NoteEvent - def note_commit_id - target.commit_id - end - - def note_short_commit_id - note_commit_id[0..8] - end - - def note_commit? - target.noteable_type == "Commit" - end - - def note_target - target.noteable - end - - def note_target_id - if note_commit? - target.commit_id - else - target.noteable_id.to_s - end - end - - def wall_note? - target.noteable_type.blank? - end - - def note_target_type - if target.noteable_type.present? - target.noteable_type.titleize - else - "Wall" - end.downcase - end -end diff --git a/app/roles/push_event.rb b/app/roles/push_event.rb deleted file mode 100644 index 8ce71b54045..00000000000 --- a/app/roles/push_event.rb +++ /dev/null @@ -1,100 +0,0 @@ -module PushEvent - def valid_push? - data[:ref] - rescue => ex - false - end - - def tag? - data[:ref]["refs/tags"] - end - - def branch? - data[:ref]["refs/heads"] - end - - def new_branch? - commit_from =~ /^00000/ - end - - def new_ref? - commit_from =~ /^00000/ - end - - def rm_ref? - commit_to =~ /^00000/ - end - - def md_ref? - !(rm_ref? || new_ref?) - end - - def commit_from - data[:before] - end - - def commit_to - data[:after] - end - - def ref_name - if tag? - tag_name - else - branch_name - end - end - - def branch_name - @branch_name ||= data[:ref].gsub("refs/heads/", "") - end - - def tag_name - @tag_name ||= data[:ref].gsub("refs/tags/", "") - end - - # Max 20 commits from push DESC - def commits - @commits ||= data[:commits].map { |commit| project.commit(commit[:id]) }.reverse - end - - def commits_count - data[:total_commits_count] || commits.count || 0 - end - - def ref_type - tag? ? "tag" : "branch" - end - - def push_action_name - if new_ref? - "pushed new" - elsif rm_ref? - "deleted" - else - "pushed to" - end - end - - def parent_commit - project.commit(commit_from) - rescue => ex - nil - end - - def last_commit - project.commit(commit_to) - rescue => ex - nil - end - - def push_with_commits? - md_ref? && commits.any? && parent_commit && last_commit - rescue Grit::NoSuchPathError - false - end - - def last_push_to_non_root? - branch? && project.default_branch != branch_name - end -end diff --git a/app/roles/push_observer.rb b/app/roles/push_observer.rb deleted file mode 100644 index dda18267207..00000000000 --- a/app/roles/push_observer.rb +++ /dev/null @@ -1,144 +0,0 @@ -# Includes methods for handling Git Push events -# -# Triggered by PostReceive job -module PushObserver - # This method will be called after each post receive and only if the provided - # user is present in GitLab. - # - # All callbacks for post receive should be placed here. - def trigger_post_receive(oldrev, newrev, ref, user) - data = post_receive_data(oldrev, newrev, ref, user) - - # Create push event - self.observe_push(data) - - if push_to_branch? ref, oldrev - # Close merged MR - self.update_merge_requests(oldrev, newrev, ref, user) - - # Execute web hooks - self.execute_hooks(data.dup) - - # Execute project services - self.execute_services(data.dup) - end - - # Create satellite - self.satellite.create unless self.satellite.exists? - - # Discover the default branch, but only if it hasn't already been set to - # something else - if default_branch.nil? - update_attributes(default_branch: discover_default_branch) - end - end - - def push_to_branch? ref, oldrev - ref_parts = ref.split('/') - - # Return if this is not a push to a branch (e.g. new commits) - !(ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000") - end - - def observe_push(data) - Event.create( - project: self, - action: Event::Pushed, - data: data, - author_id: data[:user_id] - ) - end - - def execute_hooks(data) - hooks.each { |hook| hook.execute(data) } - end - - def execute_services(data) - services.each do |service| - - # Call service hook only if it is active - service.execute(data) if service.active - end - end - - # Produce a hash of post-receive data - # - # data = { - # before: String, - # after: String, - # ref: String, - # user_id: String, - # user_name: String, - # repository: { - # name: String, - # url: String, - # description: String, - # homepage: String, - # }, - # commits: Array, - # total_commits_count: Fixnum - # } - # - def post_receive_data(oldrev, newrev, ref, user) - - push_commits = commits_between(oldrev, newrev) - - # Total commits count - push_commits_count = push_commits.size - - # Get latest 20 commits ASC - push_commits_limited = push_commits.last(20) - - # Hash to be passed as post_receive_data - data = { - before: oldrev, - after: newrev, - ref: ref, - user_id: user.id, - user_name: user.name, - repository: { - name: name, - url: web_url, - description: description, - homepage: web_url, - }, - commits: [], - total_commits_count: push_commits_count - } - - # For perfomance purposes maximum 20 latest commits - # will be passed as post receive hook data. - # - push_commits_limited.each do |commit| - data[:commits] << { - id: commit.id, - message: commit.safe_message, - timestamp: commit.date.xmlschema, - url: "#{Gitlab.config.gitlab.url}/#{path_with_namespace}/commit/#{commit.id}", - author: { - name: commit.author_name, - email: commit.author_email - } - } - end - - data - end - - def update_merge_requests(oldrev, newrev, ref, user) - return true unless ref =~ /heads/ - branch_name = ref.gsub("refs/heads/", "") - c_ids = self.commits_between(oldrev, newrev).map(&:id) - - # Update code for merge requests - mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all - 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 = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) } - mrs.each { |merge_request| merge_request.merge!(user.id) } - - true - end -end diff --git a/app/roles/static_model.rb b/app/roles/static_model.rb deleted file mode 100644 index 5b64be1f041..00000000000 --- a/app/roles/static_model.rb +++ /dev/null @@ -1,47 +0,0 @@ -# Provides an ActiveRecord-like interface to a model whose data is not persisted to a database. -module StaticModel - extend ActiveSupport::Concern - - module ClassMethods - # Used by ActiveRecord's polymorphic association to set object_id - def primary_key - 'id' - end - - # Used by ActiveRecord's polymorphic association to set object_type - def base_class - self - end - end - - # Used by AR for fetching attributes - # - # Pass it along if we respond to it. - def [](key) - send(key) if respond_to?(key) - end - - def to_param - id - end - - def new_record? - false - end - - def persisted? - false - end - - def destroyed? - false - end - - def ==(other) - if other.is_a? StaticModel - id == other.id - else - super - end - end -end diff --git a/app/roles/team.rb b/app/roles/team.rb deleted file mode 100644 index a7ba0588cf5..00000000000 --- a/app/roles/team.rb +++ /dev/null @@ -1,52 +0,0 @@ -module Team - def team_member_by_name_or_email(name = nil, email = nil) - user = users.where("name like ? or email like ?", name, email).first - users_projects.where(user: user) 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 - - # Update multiple project users - # to same access role by user ids - def update_users_ids_to_role(users_ids, access_role) - UsersProject.bulk_update(self, users_ids, access_role) - self.update_repository - end - - # Delete multiple users from project by user ids - def delete_users_ids_from_team(users_ids) - UsersProject.bulk_delete(self, users_ids) - self.update_repository - end -end diff --git a/app/roles/votes.rb b/app/roles/votes.rb deleted file mode 100644 index 10fa120c6e9..00000000000 --- a/app/roles/votes.rb +++ /dev/null @@ -1,33 +0,0 @@ -module Votes - - # Return the number of -1 comments (downvotes) - def downvotes - notes.select(&:downvote?).size - end - - def downvotes_in_percent - if votes_count.zero? - 0 - else - 100.0 - upvotes_in_percent - end - end - - # Return the number of +1 comments (upvotes) - def upvotes - notes.select(&:upvote?).size - end - - def upvotes_in_percent - if votes_count.zero? - 0 - else - 100.0 / votes_count * upvotes - end - end - - # Return the total number of votes - def votes_count - upvotes + downvotes - end -end diff --git a/app/uploaders/attachment_uploader.rb b/app/uploaders/attachment_uploader.rb index bb7dc0dab10..391731d9470 100644 --- a/app/uploaders/attachment_uploader.rb +++ b/app/uploaders/attachment_uploader.rb @@ -1,49 +1,13 @@ # encoding: utf-8 class AttachmentUploader < CarrierWave::Uploader::Base - - # Include RMagick or ImageScience support: - # include CarrierWave::RMagick - # include CarrierWave::MiniMagick - # include CarrierWave::ImageScience - - # Choose what kind of storage to use for this uploader: storage :file - # storage :fog - # Override the directory where uploaded files will be stored. - # This is a sensible default for uploaders that are meant to be mounted: def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end - # Provide a default URL as a default if there hasn't been a file uploaded: - # def default_url - # "/images/fallback/" + [version_name, "default.png"].compact.join('_') - # end - - # Process files as they are uploaded: - # process scale: [200, 300] - # - # def scale(width, height) - # # do something - # end - - # Create different versions of your uploaded files: - # version :thumb do - # process scale: [50, 50] - # end - - # Add a white list of extensions which are allowed to be uploaded. - # For images you might use something like this: - # def extension_white_list - # %w(jpg jpeg gif png) - # end - - # Override the filename of the uploaded files: - # Avoid using model.id or version_name here, see uploader/store.rb for details. - # def filename - # "something.jpg" if original_filename - # end - + def image? + %w(png jpg jpeg).include?(file.extension) + end end diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 4320bda4999..2e572aaba79 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -1,47 +1,28 @@ .admin_dash.row - .span3 + .span4 .ui-box - %h5 Projects + %h5.title Projects .data.padded = link_to admin_projects_path do %h1= Project.count %hr = link_to 'New Project', new_project_path, class: "btn small" - .span3 + .span4 .ui-box - %h5 Groups + %h5.title Groups .data.padded = link_to admin_groups_path do %h1= Group.count %hr = link_to 'New Group', new_admin_group_path, class: "btn small" - .span3 + .span4 .ui-box - %h5 Users + %h5.title Users .data.padded = link_to admin_users_path do %h1= User.count %hr = link_to 'New User', new_admin_user_path, class: "btn small" - .span3 - .ui-box - %h5 - Resque Workers - .data.padded - - if @resque_accessible - = link_to admin_resque_path do - %h1{class: @workers.present? ? "cgreen" : "cred"} - = @workers.count - %hr - %p - %strong{class: @pending_jobs > 0 ? "cred" : "cgreen"} - #{@pending_jobs} post receive jobs waiting - - else - = link_to admin_resque_path do - %h1.cdark ? - %hr - %p - %strong Resque status unknown .row .span6 diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 41f6d9b3516..0a25b125905 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -44,25 +44,57 @@ %div = f.submit 'Change Owner', class: "btn danger" = link_to "Cancel", "#", class: "btn change-owner-cancel-link" -%fieldset - %legend Projects (#{@group.projects.count}) - %table - %thead + +- if @group.projects.any? + %fieldset + %legend Projects (#{@group.projects.count}) + %table + %thead + %tr + %th Project name + %th Path + %th Users + %th.cred Danger Zone! + - @group.projects.each do |project| + %tr + %td + = link_to project.name_with_namespace, [:admin, project] + %td + %span.monospace= project.path_with_namespace + ".git" + %td= project.users.count + %td.bgred + = link_to 'Transfer project to global namespace', remove_project_admin_group_path(@group, project_id: project.id), confirm: 'Remove project from group and move to global namespace. Are you sure?', method: :delete, class: "btn danger small" + + = form_tag project_teams_update_admin_group_path(@group), id: "new_team_member", class: "bulk_import", method: :put do + %table.zebra-striped + %thead + %tr + %th Users + %th Project Access: + + - @group.users.each do |u| + %tr{class: "user_#{u.id}"} + %td.name= link_to u.name, admin_user_path(u) + %td.projects_access + - u.authorized_projects.in_namespace(@group).each do |project| + - u_p = u.users_projects.in_project(project).first + - next unless u_p + %span + = project.name + = link_to "(#{ u_p.project_access_human })", edit_admin_team_member_path(u_p) %tr - %th Project name - %th Path - %th Users - %th.cred Danger Zone! - - @group.projects.each do |project| + %td.input= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5' + %td= select_tag :project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3"} + %tr + %td= submit_tag 'Add user to projects in group', class: "btn primary" %td - = link_to project.name_with_namespace, [:admin, project] - %td - %span.monospace= project.path_with_namespace + ".git" - %td= project.users.count - %td.bgred - = link_to 'Transfer project to global namespace', remove_project_admin_group_path(@group, project_id: project.id), confirm: 'Remove project from group and move to global namespace. Are you sure?', method: :delete, class: "btn danger small" + Read more about project permissions + %strong= link_to "here", help_permissions_path, class: "vlink" +- else + %fieldset + %legend Group is empty = form_tag project_update_admin_group_path(@group), class: "bulk_import", method: :put do %fieldset diff --git a/app/views/admin/projects/_form.html.haml b/app/views/admin/projects/_form.html.haml index 27c22872d50..36c0c655cae 100644 --- a/app/views/admin/projects/_form.html.haml +++ b/app/views/admin/projects/_form.html.haml @@ -11,18 +11,18 @@ .input = f.text_field :name, placeholder: "Example Project", class: "xxlarge" - %fieldset.adv_settings - %legend Advanced settings: - .clearfix - = f.label :path do - Path - .input - = text_field_tag :ppath, @project.path_to_repo, class: "xlarge", disabled: true + - if project.repo_exists? + %fieldset.adv_settings + %legend Advanced settings: + .clearfix + = f.label :path do + Path + .input + = text_field_tag :ppath, @project.repository.path_to_repo, class: "xlarge", disabled: true - - if project.repo_exists? .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.repository.heads.map(&:name), {}, style: "width:210px;") %fieldset.adv_settings %legend Features: diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index 310cfa53890..1f5b31eca5f 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -1,5 +1,5 @@ %h3.page_title - Projects (#{@projects.count}) + Projects (#{Project.count}) = link_to 'New Project', new_project_path, class: "btn small right" %br = form_tag admin_projects_path, method: :get, class: 'form-inline' do @@ -15,6 +15,7 @@ %i.icon-sort-down %th Path %th Team Members + %th Owner %th Last Commit %th Edit %th.cred Danger Zone! @@ -26,6 +27,11 @@ %td %span.monospace= project.path_with_namespace + ".git" %td= project.users_projects.count + %td + - if project.owner + = link_to project.owner.name, [:admin, project.owner] + - else + (deleted) %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" diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index 634b1836754..5a745f58fe3 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -4,15 +4,15 @@ %i.icon-edit Edit -- if @project.has_commits? - - if !@project.has_post_receive_file? +- if @repository && @repository.has_commits? + - if !@repository.has_post_receive_file? %br .alert.alert-error %span %strong Project has commits but missing post-receive file. %br If you exported project manually - make a link of post-receive hook file from gitolite to project repository - - elsif !@project.valid_post_receive_file? + - elsif !@repository.valid_post_receive_file? %br .alert.alert-error %span @@ -49,8 +49,8 @@ %b Owned by: %td - - if @project.chief - = link_to @project.chief.name, admin_user_path(@project.chief) + - if @project.owner + = link_to @project.owner_name, admin_user_path(@project.owner) - else (deleted) %tr @@ -58,49 +58,50 @@ %b Created by: %td - = @project.owner_name || '(deleted)' + = @project.creator.try(:name) || '(deleted)' %tr %td %b Created at: %td = @project.created_at.stamp("March 1, 1999") + %tr + %td + %b + Smart HTTP: + %td + = link_to @project.http_url_to_repo + %tr + %td + %b + SSH: + %td + = link_to @project.ssh_url_to_repo -%table.zebra-striped - %thead +- if @repository + %table.zebra-striped + %thead + %tr + %th Repository + %th %tr - %th Repository - %th - %tr - %td - %b - FS Path: - %td - %code= @project.path_to_repo - %tr - %td - %b - Smart HTTP: - %td - = link_to @project.http_url_to_repo - %tr - %td - %b - SSH: - %td - = link_to @project.ssh_url_to_repo - %tr - %td - %b - Last commit at: - %td - = last_commit(@project) - %tr - %td - %b - Post Receive File: - %td - = check_box_tag :post_receive_file, 1, @project.has_post_receive_file?, disabled: true + %td + %b + FS Path: + %td + %code= @repository.path_to_repo + %tr + %td + %b + Last commit at: + %td + = last_commit(@project) + %tr + %td + %b + Post Receive File: + %td + = check_box_tag :post_receive_file, 1, @repository.has_post_receive_file?, disabled: true %br %h5 diff --git a/app/views/admin/resque/show.html.haml b/app/views/admin/resque/show.html.haml index 41254a6b6c2..499738f9a06 100644 --- a/app/views/admin/resque/show.html.haml +++ b/app/views/admin/resque/show.html.haml @@ -1,4 +1,4 @@ -%h3.page_title Resque +%h3.page_title Background Jobs %br .ui-box - %iframe{src: resque_path, width: '100%', height: 600, style: "border: none"} + %iframe{src: sidekiq_path, width: '100%', height: 900, style: "border: none"} diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index 1df4f590bcb..87290abe7a6 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -1,5 +1,5 @@ %h3.page_title - Users (#{@admin_users.count}) + Users = link_to 'New User', new_admin_user_path, class: "btn small right" %br @@ -8,16 +8,21 @@ = submit_tag "Search", class: "btn submit primary" %ul.nav.nav-tabs %li{class: "#{'active' unless params[:filter]}"} - = link_to "Active", admin_users_path + = link_to admin_users_path do + Active + %span.badge= User.active.count %li{class: "#{'active' if params[:filter] == "admins"}"} = link_to admin_users_path(filter: "admins") do Admins + %span.badge= User.admins.count %li{class: "#{'active' if params[:filter] == "blocked"}"} = link_to admin_users_path(filter: "blocked") do Blocked + %span.badge= User.blocked.count %li{class: "#{'active' if params[:filter] == "wop"}"} = link_to admin_users_path(filter: "wop") do Without projects + %span.badge= User.without_projects.count %table %thead diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index 852aead79e2..db132359c7f 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -106,8 +106,8 @@ %td= link_to group.name, admin_group_path(group) -- if @admin_user.projects.present? - %h5 Projects: +- if @admin_user.personal_projects.present? + %h5 Personal Projects: %br %table.zebra-striped @@ -118,7 +118,7 @@ %th %th - - @admin_user.users_projects.each do |tm| + - @admin_user.tm_in_personal_projects.each do |tm| - project = tm.project %tr %td= link_to project.name_with_namespace, admin_project_path(project) diff --git a/app/views/commit/show.html.haml b/app/views/commit/show.html.haml index 5ba43f951dc..f920534e03a 100644 --- a/app/views/commit/show.html.haml +++ b/app/views/commit/show.html.haml @@ -1,4 +1,11 @@ = render "commits/commit_box" + +%p.right.cgray + This commit has + %span.cgreen #{@commit.stats.additions} additions + and + %span.cred #{@commit.stats.deletions} deletions + = render "commits/diffs", diffs: @commit.diffs = render "notes/notes_with_form" @@ -16,5 +23,7 @@ , h = event.currentTarget.naturalHeight; $('.image.diff_added .image-info', this).append(' | <b>W:</b> ' + w + 'px | <b>H:</b> ' + h + 'px'); }, this)); + }); + }); diff --git a/app/views/commits/_commit.html.haml b/app/views/commits/_commit.html.haml index 156ff1e9d85..eb0312d01e1 100644 --- a/app/views/commits/_commit.html.haml +++ b/app/views/commits/_commit.html.haml @@ -14,8 +14,8 @@ %span.notes_count - - notes = @project.commit_notes(commit) + @project.commit_line_notes(commit) + - notes = @project.notes.for_commit_id(commit.id) - if notes.any? - %span.btn.small.disabled.grouped + %span.btn.disabled.grouped %i.icon-comment = notes.count diff --git a/app/views/commits/_commit_box.html.haml b/app/views/commits/_commit_box.html.haml index 8f7826e0c8d..0544a1d10fe 100644 --- a/app/views/commits/_commit_box.html.haml +++ b/app/views/commits/_commit_box.html.haml @@ -1,47 +1,50 @@ -.commit-box{class: @commit.parents_count > 1 ? "merge-commit" : ""} - .commit-head +.ui-box.ui-box-show + .ui-box-head .right - if @notes_count > 0 %span.btn.disabled.grouped %i.icon-comment = @notes_count .left.btn-group - %a.btn.small.grouped.dropdown-toggle{ data: {toggle: :dropdown} } + %a.btn.grouped.dropdown-toggle{ data: {toggle: :dropdown} } %i.icon-download-alt Download as %span.caret %ul.dropdown-menu %li= link_to "Email Patches", project_commit_path(@project, @commit, format: :patch) %li= link_to "Plain Diff", project_commit_path(@project, @commit, format: :diff) - = link_to project_tree_path(@project, @commit), class: "browse-button primary grouped" do - %strong Browse Code » + = link_to project_tree_path(@project, @commit), class: "btn primary grouped" do + %span Browse Code » %h3.commit-title.page_title = gfm escape_once(@commit.title) - if @commit.description.present? %pre.commit-description = gfm escape_once(@commit.description) - .commit-info + .ui-box-body .row .span5 .author - %strong= @commit.author_link avatar: true, size: 40 + = @commit.author_link avatar: true, size: 32 authored %time{title: @commit.authored_date.stamp("Aug 21, 2011 9:23pm")} #{time_ago_in_words(@commit.authored_date)} ago - if @commit.different_committer? .committer → - %strong= @commit.committer_link + = @commit.committer_link committed %time{title: @commit.committed_date.stamp("Aug 21, 2011 9:23pm")} #{time_ago_in_words(@commit.committed_date)} ago - .span6.right - .sha-block - %span.cgray commit - %code.label_commit= @commit.id - .sha-block - %span.cgray= pluralize(@commit.parents.count, "parent") - - @commit.parents.each do |parent| - = link_to parent.id[0...10], project_commit_path(@project, parent) + .span6.pull-right + .pull-right + .sha-block + %span.cgray commit + %span.label_commit= @commit.id + .clearfix + .pull-right + .sha-block + %span.cgray= pluralize(@commit.parents.count, "parent") + - @commit.parents.each do |parent| + = link_to parent.id[0...10], project_commit_path(@project, parent) diff --git a/app/views/commits/_commits.html.haml b/app/views/commits/_commits.html.haml index c9217989884..0dc6664c1d6 100644 --- a/app/views/commits/_commits.html.haml +++ b/app/views/commits/_commits.html.haml @@ -1,6 +1,6 @@ - @commits.group_by { |c| c.committed_date.to_date }.each do |day, commits| %div.ui-box - %h5.small + %h5.title %i.icon-calendar = day.stamp("28 Aug, 2010") %ul.well-list= render commits diff --git a/app/views/commits/_head.html.haml b/app/views/commits/_head.html.haml index 2ec1d24bbef..a5f3fdf5c5e 100644 --- a/app/views/commits/_head.html.haml +++ b/app/views/commits/_head.html.haml @@ -2,19 +2,19 @@ %li= render partial: 'shared/ref_switcher', locals: {destination: 'commits'} = nav_link(controller: [:commit, :commits]) do - = link_to 'Commits', project_commits_path(@project, @project.root_ref) + = link_to 'Commits', project_commits_path(@project, @repository.root_ref) = nav_link(controller: :compare) do = link_to 'Compare', project_compare_index_path(@project) = nav_link(html_options: {class: branches_tab_class}) do = link_to project_repository_path(@project) do Branches - %span.badge= @project.branches.length + %span.badge= @repository.branches.length = nav_link(controller: :repositories, action: :tags) do = link_to tags_project_repository_path(@project) do Tags - %span.badge= @project.tags.length + %span.badge= @repository.tags.length = nav_link(controller: :repositories, action: :stats) do = link_to stats_project_repository_path(@project) do diff --git a/app/views/commits/_text_diff.html.haml b/app/views/commits/_text_diff.html.haml index f5784dea511..ce07b87d548 100644 --- a/app/views/commits/_text_diff.html.haml +++ b/app/views/commits/_text_diff.html.haml @@ -15,7 +15,7 @@ - if @comments_allowed = render "notes/diff_note_link", line_code: line_code %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} " + %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line) - if @reply_allowed - comments = @line_notes.select { |n| n.line_code == line_code }.sort_by(&:created_at) diff --git a/app/views/compare/_form.html.haml b/app/views/compare/_form.html.haml index 7e3a2a0e1f5..0915782dddc 100644 --- a/app/views/compare/_form.html.haml +++ b/app/views/compare/_form.html.haml @@ -28,7 +28,7 @@ :javascript $(function() { - var availableTags = #{@project.ref_names.to_json}; + var availableTags = #{@project.repository.ref_names.to_json}; $("#from, #to").autocomplete({ source: availableTags, diff --git a/app/views/compare/show.html.haml b/app/views/compare/show.html.haml index 2abbd3fc0ee..d8ea3727d57 100644 --- a/app/views/compare/show.html.haml +++ b/app/views/compare/show.html.haml @@ -8,7 +8,8 @@ - if @commits.present? %div.ui-box - %h5.small Commits (#{@commits.count}) + %h5.title + Commits (#{@commits.count}) %ul.well-list= render @commits - unless @diffs.empty? diff --git a/app/views/dashboard/_activities.html.haml b/app/views/dashboard/_activities.html.haml index c63ef24fca5..2b7d23c225d 100644 --- a/app/views/dashboard/_activities.html.haml +++ b/app/views/dashboard/_activities.html.haml @@ -7,7 +7,7 @@ = event_filter_link EventFilter.team, 'Team' - if @events.any? - .content_list= render @events + .content_list - else %p.nothing_here_message Projects activity will be displayed here .loading.hide diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml index 9e3401e51b8..7f544406761 100644 --- a/app/views/dashboard/_groups.html.haml +++ b/app/views/dashboard/_groups.html.haml @@ -1,5 +1,5 @@ .groups_box - %h5 + %h5.title Groups %small (#{groups.count}) @@ -17,4 +17,4 @@ → %span.last_activity %strong Projects: - %span= group.projects.authorized_for(current_user).count + %span= current_user.authorized_projects.where(namespace_id: group.id).count diff --git a/app/views/dashboard/_projects.html.haml b/app/views/dashboard/_projects.html.haml index cffafb5445c..6c1304ee4a8 100644 --- a/app/views/dashboard/_projects.html.haml +++ b/app/views/dashboard/_projects.html.haml @@ -1,5 +1,5 @@ .projects_box - %h5 + %h5.title Projects %small (#{projects.total_count}) diff --git a/app/views/dashboard/index.html.haml b/app/views/dashboard/index.html.haml index b64aa86cf73..abbe3101fc3 100644 --- a/app/views/dashboard/index.html.haml +++ b/app/views/dashboard/index.html.haml @@ -7,5 +7,3 @@ - else = render "zero_authorized_projects" -:javascript - $(function(){ Pager.init(20); }); diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml index 52863229644..68e3b3dcaf5 100644 --- a/app/views/dashboard/issues.html.haml +++ b/app/views/dashboard/issues.html.haml @@ -13,7 +13,8 @@ - @issues.group_by(&:project).each do |group| %div.ui-box - @project = group[0] - %h5= link_to_project @project + %h5.title + = link_to_project @project %ul.well-list.issues_table - group[1].each do |issue| = render(partial: 'issues/show', locals: {issue: issue}) diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml index ea7c8c9a3d5..c5245da731a 100644 --- a/app/views/dashboard/merge_requests.html.haml +++ b/app/views/dashboard/merge_requests.html.haml @@ -12,7 +12,8 @@ - @merge_requests.group_by(&:project).each do |group| .ui-box - @project = group[0] - %h5= link_to_project @project + %h5.title + = link_to_project @project %ul.well-list - group[1].each do |merge_request| = render(partial: 'merge_requests/merge_request', locals: {merge_request: merge_request}) diff --git a/app/views/events/event/_note.html.haml b/app/views/events/event/_note.html.haml index 8c12969345f..7b57f424d61 100644 --- a/app/views/events/event/_note.html.haml +++ b/app/views/events/event/_note.html.haml @@ -19,7 +19,6 @@ = event.project_name .event-body - %span.hint - - %i.icon-comment + %span.event-note + %i.icon-comment-alt = truncate event.target.note, length: 70 diff --git a/app/views/groups/_filter.html.haml b/app/views/groups/_filter.html.haml new file mode 100644 index 00000000000..c8b0ad0f433 --- /dev/null +++ b/app/views/groups/_filter.html.haml @@ -0,0 +1,33 @@ += form_tag group_filter_path(entity), method: 'get' do + %fieldset.dashboard-search-filter + = search_field_tag "search", params[:search], { placeholder: 'Search', class: 'search-text-input' } + = button_tag type: 'submit', class: 'btn' do + %i.icon-search + + %fieldset + %legend Status: + %ul.nav.nav-pills.nav-stacked + %li{class: ("active" if !params[:status])} + = link_to group_filter_path(entity, status: nil) do + Open + %li{class: ("active" if params[:status] == 'closed')} + = link_to group_filter_path(entity, status: 'closed') do + Closed + %li{class: ("active" if params[:status] == 'all')} + = link_to group_filter_path(entity, status: 'all') do + All + + %fieldset + %legend Projects: + %ul.nav.nav-pills.nav-stacked + - @projects.each do |project| + - unless entities_per_project(project, entity).zero? + %li{class: ("active" if params[:project_id] == project.id.to_s)} + = link_to group_filter_path(entity, project_id: project.id) do + = project.name_with_namespace + %small.right= entities_per_project(project, entity) + + %fieldset + %hr + = link_to "Reset", group_filter_path(entity), class: 'btn right' + diff --git a/app/views/groups/_new_group_member.html.haml b/app/views/groups/_new_group_member.html.haml new file mode 100644 index 00000000000..2d599816e2a --- /dev/null +++ b/app/views/groups/_new_group_member.html.haml @@ -0,0 +1,18 @@ += form_for @team_member, as: :team_member, url: team_members_group_path(@group) do |f| + %fieldset + %legend= "New Team member(s) for projects in #{@group.name}" + + %h6 1. Choose people you want in the team + .clearfix + = f.label :user_ids, "People" + .input= select_tag(:user_ids, options_from_collection_for_select(User.active.alphabetically, :id, :name), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true}) + + %h6 2. Set access level for them + .clearfix + = f.label :project_access, "Project Access" + .input= select_tag :project_access, options_for_select(Project.access_options, @team_member.project_access), class: "project-access-select chosen" + + .form-actions + = hidden_field_tag :redirect_to, people_group_path(@group) + = f.submit 'Add', class: "btn save-btn" + diff --git a/app/views/groups/_new_member.html.haml b/app/views/groups/_new_member.html.haml index f48c2c23d83..89ac05e774e 100644 --- a/app/views/groups/_new_member.html.haml +++ b/app/views/groups/_new_member.html.haml @@ -5,7 +5,7 @@ %h6 1. Choose people you want in the team .clearfix = f.label :user_ids, "People" - .input= select_tag(:user_ids, options_from_collection_for_select(User.not_in_project(@project).all, :id, :name), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true}) + .input= select_tag(:user_ids, options_from_collection_for_select(User.not_in_project(@project).alphabetically, :id, :name), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true}) %h6 2. Set access level for them .clearfix diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml index 0b491879fe0..040d1ae94aa 100644 --- a/app/views/groups/_projects.html.haml +++ b/app/views/groups/_projects.html.haml @@ -1,5 +1,5 @@ .projects_box - %h5 + %h5.title Projects %small (#{projects.count}) diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml index 0daf4d752a8..ffca2dc75ea 100644 --- a/app/views/groups/issues.html.haml +++ b/app/views/groups/issues.html.haml @@ -3,17 +3,21 @@ %small (assigned to you) %small.right #{@issues.total_count} issues -%br -.clearfix -- if @issues.any? - - @issues.group_by(&:project).each do |group| - %div.ui-box - - @project = group[0] - %h5= @project.name - %ul.well-list.issues_table - - group[1].each do |issue| - = render(partial: 'issues/show', locals: {issue: issue}) - %hr - = paginate @issues, theme: "gitlab" -- else - %h3.nothing_here_message Nothing to show here +%hr +.row + .span3 + = render 'filter', entity: 'issue' + .span9 + - if @issues.any? + - @issues.group_by(&:project).each do |group| + %div.ui-box + - @project = group[0] + %h5.title + = link_to_project @project + %ul.well-list.issues_table + - group[1].each do |issue| + = render(partial: 'issues/show', locals: {issue: issue}) + %hr + = paginate @issues, theme: "gitlab" + - else + %p.nothing_here_message Nothing to show here diff --git a/app/views/groups/merge_requests.html.haml b/app/views/groups/merge_requests.html.haml index 72aa4ad11e1..c5245da731a 100644 --- a/app/views/groups/merge_requests.html.haml +++ b/app/views/groups/merge_requests.html.haml @@ -3,16 +3,22 @@ %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.well-list.ui-box - - @project = group[0] - %h5= @project.name - - group[1].each do |merge_request| - = render(partial: 'merge_requests/merge_request', locals: {merge_request: merge_request}) - %hr - = paginate @merge_requests, theme: "gitlab" +%hr +.row + .span3 + = render 'filter', entity: 'merge_request' + .span9 + - if @merge_requests.any? + - @merge_requests.group_by(&:project).each do |group| + .ui-box + - @project = group[0] + %h5.title + = link_to_project @project + %ul.well-list + - group[1].each do |merge_request| + = render(partial: 'merge_requests/merge_request', locals: {merge_request: merge_request}) + %hr + = paginate @merge_requests, theme: "gitlab" -- else - %h3.nothing_here_message Nothing to show here + - else + %h3.nothing_here_message Nothing to show here diff --git a/app/views/groups/people.html.haml b/app/views/groups/people.html.haml index be3dd7a4d78..0bceeaa3ceb 100644 --- a/app/views/groups/people.html.haml +++ b/app/views/groups/people.html.haml @@ -2,10 +2,10 @@ .span3 = render 'people_filter' .span9 - - if @project && can?(current_user, :manage_group, @group) - = render "new_member" + - if can?(current_user, :manage_group, @group) + = render (@project ? "new_member" : "new_group_member") .ui-box - %h5 + %h5.title Team %small (#{@users.size}) diff --git a/app/views/groups/search.html.haml b/app/views/groups/search.html.haml index 6ca5630f43d..1ba4707aa52 100644 --- a/app/views/groups/search.html.haml +++ b/app/views/groups/search.html.haml @@ -6,70 +6,4 @@ = search_field_tag :search, params[:search], placeholder: "issue 143", class: "input-xxlarge search-text-input", id: "dashboard_search" = submit_tag 'Search', class: "btn primary wide" - if params[:search].present? - %br - %h3 - Search results - %small (#{@projects.count + @merge_requests.count + @issues.count}) - %hr - .search_results - .row - .span6 - %table - %thead - %tr - %th Projects - %tbody - - @projects.each do |project| - %tr - %td - = link_to project do - %strong.term= project.name - %small.cgray - last activity at - = project.last_activity_date.stamp("Aug 25, 2011") - - if @projects.blank? - %tr - %td - %h4.nothing_here_message No Projects - %br - %table - %thead - %tr - %th Merge Requests - %tbody - - @merge_requests.each do |merge_request| - %tr - %td - = link_to [merge_request.project, merge_request] do - %span.badge.badge-info ##{merge_request.id} - – - %strong.term= truncate merge_request.title, length: 50 - %strong.right - %span.label= merge_request.project.name - - if @merge_requests.blank? - %tr - %td - %h4.nothing_here_message No Merge Requests - .span6 - %table - %thead - %tr - %th Issues - %tbody - - @issues.each do |issue| - %tr - %td - = link_to [issue.project, issue] do - %span.badge.badge-info ##{issue.id} - – - %strong.term= truncate issue.title, length: 40 - %strong.right - %span.label= issue.project.name - - if @issues.blank? - %tr - %td - %h4.nothing_here_message No Issues - :javascript - $(function() { - $(".search_results .term").highlight("#{params[:search]}"); - }) + = render 'search/result' diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 76bc2639d61..d7d3f869895 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -7,7 +7,7 @@ %span.cgray Events and projects are filtered in scope of group %hr - if @events.any? - .content_list= render @events + .content_list - else %p.nothing_here_message Projects activity will be displayed here .loading.hide @@ -26,4 +26,4 @@ = link_to "@gitlabhq", "https://twitter.com/gitlabhq" :javascript - $(function(){ Pager.init(20); }); + $(function(){ Pager.init(20, true); }); diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index ebd499c05e0..dc22b672cb7 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -9,31 +9,41 @@ %br Fast, secure and stable solution based on Ruby on Rails & Gitolite. -%hr +%br + +.row + .span6 + .ui-box + .title + %h5 Help + %ul.well-list + %li + %span= link_to "Workflow", help_workflow_path -%h3 Help + %li + %span= link_to "Permissions", help_permissions_path -%ol - %li - %h5= link_to "Workflow", help_workflow_path + %li + %span= link_to "Web Hooks", help_web_hooks_path - %li - %h5= link_to "Permissions", help_permissions_path + %li + %span= link_to "API", help_api_path - %li - %h5= link_to "Web Hooks", help_web_hooks_path + %li + %span= link_to "GitLab Markdown", help_markdown_path - %li - %h5= link_to "System Hooks", help_system_hooks_path + %li + %span= link_to "SSH keys", help_ssh_path - %li - %h5= link_to "API", help_api_path + .span6 + .ui-box + .title + %h5 Admin Guide + %ul.well-list - %li - %h5= link_to "GitLab Markdown", help_markdown_path + %li + %span= link_to "GitLab Rake Tasks", help_raketasks_path - %li - %h5= link_to "SSH keys", help_ssh_path + %li + %span= link_to "System Hooks", help_system_hooks_path - %li - %h5= link_to "GitLab Rake Tasks", help_raketasks_path diff --git a/app/views/help/markdown.html.haml b/app/views/help/markdown.html.haml index aa608ed6d9a..0419f7c131a 100644 --- a/app/views/help/markdown.html.haml +++ b/app/views/help/markdown.html.haml @@ -1,6 +1,6 @@ %h3.page_title GitLab Flavored Markdown .back_link - = link_to help_path do + = link_to help_path do ← to index %hr @@ -120,7 +120,7 @@ for commits -# this example will only be shown if the user has a project with at least one issue - - if @project = current_user.projects.first + - if @project = current_user.authorized_projects.first - if issue = @project.issues.first %p For example in your #{link_to @project.name, project_path(@project)} project, writing: %pre= "This is related to ##{issue.id}. @#{current_user.name} is working on solving it." diff --git a/app/views/help/raketasks.html.haml b/app/views/help/raketasks.html.haml index 62cfa1521a7..f015451a673 100644 --- a/app/views/help/raketasks.html.haml +++ b/app/views/help/raketasks.html.haml @@ -16,6 +16,8 @@ = link_to "User Management", "#user_management", 'data-toggle' => 'tab' %li = link_to "Backup & Restore", "#backup_restore", 'data-toggle' => 'tab' + %li + = link_to "Cleanup", "#cleanup", 'data-toggle' => 'tab' .tab-content .tab-pane.active#features @@ -45,6 +47,15 @@ = preserve do = markdown File.read(Rails.root.join("doc", "raketasks", "user_management.md")) + .tab-pane#cleanup + .file_holder + .file_title + %i.icon-file + Cleanup + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "raketasks", "cleanup.md")) + .tab-pane#backup_restore .file_holder .file_title diff --git a/app/views/hooks/_data_ex.html.erb b/app/views/hooks/_data_ex.html.erb index 7dd6b9e0750..b4281fa18c7 100644 --- a/app/views/hooks/_data_ex.html.erb +++ b/app/views/hooks/_data_ex.html.erb @@ -1,45 +1,43 @@ <% data_ex_str = <<eos { - :before => "95790bf891e76fee5e1747ab589903a6a1f80f22", - :after => "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", - :ref => "refs/heads/master", - :user_id => 4, - :user_name => "John Smith", - :repository => { - :name => "Diaspora", - :url => "localhost/diaspora", - :description => "", - :homepage => "localhost/diaspora", - :private => true + "before": "95790bf891e76fee5e1747ab589903a6a1f80f22", + "after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", + "ref": "refs/heads/master", + "user_id": 4, + "user_name": "John Smith", + "repository": { + "name": "Diaspora", + "url": "git@localhost:diaspora.git", + "description": "", + "homepage": "http://localhost/diaspora", + }, + "commits": [ + { + "id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", + "message": "Update Catalan translation to e38cb41.", + "timestamp": "2011-12-12T14:27:31+02:00", + "url": "http://localhost/diaspora/commits/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", + "author": { + "name": "Jordi Mallach", + "email": "jordi@softcatala.org", + } }, - :commits => [ - [0] { - :id => "450d0de7532f8b663b9c5cce183b...", - :message => "Update Catalan translation to e38cb41.", - :timestamp => "2011-12-12T14:27:31+02:00", - :url => "http://localhost/diaspora/commits/450d0de7532f...", - :author => { - :name => "Jordi Mallach", - :email => "jordi@softcatala.org" - } - }, - - .... - - [3] { - :id => "da1560886d4f094c3e6c9ef40349...", - :message => "fixed readme", - :timestamp => "2012-01-03T23:36:29+02:00", - :url => "http://localhost/diaspora/commits/da1560886d...", - :author => { - :name => "GitLab dev user", - :email => "gitlabdev@dv6700.(none)" - } - } - ], - total_commits_count => 4 -} + // ... + { + "id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", + "message": "fixed readme", + "timestamp": "2012-01-03T23:36:29+02:00", + "url": "http://localhost/diaspora/commits/da1560886d4f094c3e6c9ef40349f7d38b5d27d7", + "author": { + "name": "GitLab dev user", + "email": "gitlabdev@dv6700.(none)", + }, + }, + ], + "total_commits_count": 4, +}; eos %> -<% js_lexer = Pygments::Lexer[:js] %> -<%= raw js_lexer.highlight(data_ex_str) %> +<div class="<%= user_color_scheme_class%>"> + <%= raw Pygments::Lexer[:js].highlight(data_ex_str) %> +</div> diff --git a/app/views/issues/_filter.html.haml b/app/views/issues/_filter.html.haml new file mode 100644 index 00000000000..9b710a71772 --- /dev/null +++ b/app/views/issues/_filter.html.haml @@ -0,0 +1,20 @@ += form_tag project_issues_path(@project), method: 'get' do + %fieldset + %ul.nav.nav-pills.nav-stacked + %li{class: ("active" if !params[:status])} + = link_to project_issues_path(@project, status: nil) do + Open + %li{class: ("active" if params[:status] == 'to_me')} + = link_to project_issues_path(@project, status: 'to_me') do + Assigned To Me + %li{class: ("active" if params[:status] == 'closed')} + = link_to project_issues_path(@project, status: 'closed') do + Closed + %li{class: ("active" if params[:status] == 'all')} + = link_to project_issues_path(@project, status: 'all') do + All + + %fieldset + %hr + = link_to "Reset", project_issues_path(@project), class: 'btn right' + diff --git a/app/views/issues/_form.html.haml b/app/views/issues/_form.html.haml index 030f797c088..bef235f2dea 100644 --- a/app/views/issues/_form.html.haml +++ b/app/views/issues/_form.html.haml @@ -6,26 +6,27 @@ - @issue.errors.full_messages.each do |msg| %span= msg %br - .issue_form_box - .issue_title + .ui-box.ui-box-show + .ui-box-head .clearfix = f.label :title do %strong= "Subject *" .input = f.text_field :title, maxlength: 255, class: "xxlarge js-gfm-input", autofocus: true, required: true - .issue_middle_block - .issue_assignee - = 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" }, {class: 'chosen'}) - .issue_milestone - = 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" }, {class: 'chosen'}) + .ui-box-body + .clearfix + .issue_assignee.pull-left + = 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" }, {class: 'chosen'}) + .issue_milestone.pull-left + = 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" }, {class: 'chosen'}) - .issue_description + .ui-box-bottom .clearfix = f.label :label_list do %i.icon-tag @@ -43,7 +44,7 @@ .actions - if @issue.new_record? - = f.submit 'Submit new issue', class: "btn save-btn" + = f.submit 'Submit new issue', class: "btn success" -else = f.submit 'Save changes', class: "save-btn btn" diff --git a/app/views/issues/_issues.html.haml b/app/views/issues/_issues.html.haml index d7ba4300ce7..8821dbb8d98 100644 --- a/app/views/issues/_issues.html.haml +++ b/app/views/issues/_issues.html.haml @@ -3,12 +3,10 @@ - if @issues.present? %li.bottom - .row - .span7= paginate @issues, remote: true, theme: "gitlab" - .span3.right - %span.cgray.right - %span.issue_counter #{@issues.total_count} - issues for this filter + .left= paginate @issues, remote: true, theme: "gitlab" + .right + %span.issue_counter #{@issues.total_count} + issues for this filter - 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 4641e8bdc63..dcef901c15f 100644 --- a/app/views/issues/_show.html.haml +++ b/app/views/issues/_show.html.haml @@ -3,10 +3,6 @@ .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-tag.grouped - %i.icon-tag - = label.name - if issue.notes.any? %span.btn.small.disabled.grouped %i.icon-comment @@ -36,3 +32,8 @@ - if issue.votes_count > 0 = render 'votes/votes_inline', votable: issue + %span + - issue.labels.each do |label| + %span.label + %i.icon-tag + = label.name diff --git a/app/views/issues/index.html.haml b/app/views/issues/index.html.haml index 08d4393b201..d5c29c780ce 100644 --- a/app/views/issues/index.html.haml +++ b/app/views/issues/index.html.haml @@ -2,61 +2,47 @@ .issues_content %h3.page_title Issues - %small (<span class=issue_counter>#{@issues.total_count}</span>) + %span (<span class=issue_counter>#{@issues.total_count}</span>) .right .span5 - if can? current_user, :write_issue, @project - = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "right btn", title: "New Issue", id: "new_issue_link" do + = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "right btn primary", title: "New Issue", id: "new_issue_link" 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' } - = hidden_field_tag :status, params[:f] + = hidden_field_tag :status, params[:status] = search_field_tag :issue_search, nil, { placeholder: 'Search', class: 'issue_search span3 right neib search-text-input' } .clearfix - %div#issues-table-holder.ui-box - .title - = 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(issues_active_milestones, "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] + issues_active_milestones, "id", "title", params[:milestone_id]), prompt: "Milestone") - = hidden_field_tag :f, params[:f] +.row + .span3 + = render 'filter', entity: 'issue' + .span9 + %div#issues-table-holder.ui-box + .title + = check_box_tag "check_all_issues", nil, false, class: "check_all_issues left" .clearfix + .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(issues_active_milestones, "id", "title", params[:milestone_id]), prompt: "Milestone") + = hidden_field_tag 'update[issues_ids]', [] + = hidden_field_tag :status, params[:status] + = button_tag "Save", class: "btn update_selected_issues btn-small save-btn" + .issues_filters + = form_tag project_issues_path(@project), method: :get 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] + issues_active_milestones, "id", "title", params[:milestone_id]), prompt: "Milestone") + = hidden_field_tag :status, params[:status] - %ul#issues-table.well-list.issues_table - = render "issues" + %ul#issues-table.well-list.issues_table + = render "issues" :javascript $(function(){ diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index b1014edc6c5..55fc0aee0df 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -24,14 +24,14 @@ ← To issues list -.main_box - .top_box_content +.ui-box.ui-box-show + .ui-box-head %h4.box-title - if @issue.closed .error.status_info Closed = gfm escape_once(@issue.title) - .middle_box_content + .ui-box-body %cite.cgray Created by #{link_to_member(@project, @issue.author)} - if @issue.assignee @@ -44,13 +44,13 @@ .right - @issue.labels.each do |label| - %span.label.label-issue + %span.label %i.icon-tag = label.name - if @issue.description.present? - .bottom_box_content + .ui-box-bottom = preserve do = markdown @issue.description diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index 4a0f60d36c2..9d035f0e012 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -1,8 +1,8 @@ %head %meta{charset: "utf-8"} %title + = "#{title} | " if defined?(title) GitLab - = " > #{title}" if defined?(title) = favicon_link_tag 'favicon.ico' = stylesheet_link_tag "application" = javascript_include_tag "application" diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml index 8fbec43f4a1..f4b2228a41b 100644 --- a/app/views/layouts/_head_panel.html.haml +++ b/app/views/layouts/_head_panel.html.haml @@ -2,7 +2,8 @@ .navbar-inner .container %div.app_logo - = link_to root_path, class: "home", title: "Home" do + %span.separator + = link_to root_path, class: "home has_bottom_tooltip", title: "Dashboard" do %h1 GITLAB %span.separator %h1.project_name= title diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml index 6b643ec8ccb..a60e7febe76 100644 --- a/app/views/layouts/admin.html.haml +++ b/app/views/layouts/admin.html.haml @@ -19,6 +19,6 @@ = nav_link(controller: :hooks) do = link_to "Hooks", admin_hooks_path = nav_link(controller: :resque) do - = link_to "Resque", admin_resque_path + = link_to "Background Jobs", admin_resque_path .content= yield diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index a41de538436..a197de38749 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -15,7 +15,7 @@ = nav_link(path: 'dashboard#merge_requests') do = link_to dashboard_merge_requests_path do Merge Requests - %span.count= current_user.cared_merge_requests.count + %span.count= current_user.cared_merge_requests.opened.count = nav_link(path: 'search#show') do = link_to "Search", search_path = nav_link(path: 'help#index') do diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml index d40d9525bb8..f47e8b3e9ff 100644 --- a/app/views/layouts/group.html.haml +++ b/app/views/layouts/group.html.haml @@ -15,7 +15,7 @@ = nav_link(path: 'groups#merge_requests') do = link_to merge_requests_group_path(@group) do Merge Requests - %span.count= current_user.cared_merge_requests.of_group(@group).count + %span.count= current_user.cared_merge_requests.opened.of_group(@group).count = nav_link(path: 'groups#search') do = link_to "Search", search_group_path(@group) = nav_link(path: 'groups#people') do diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml index c418e1dbc68..3db1f59b54d 100644 --- a/app/views/layouts/notify.html.haml +++ b/app/views/layouts/notify.html.haml @@ -13,10 +13,10 @@ %td{style: "font-size: 0px;", width: "20"} \ %td{align: "left", style: "padding: 10px 0", width: "580"} - %h1{style: "font-size: 24px; color: #BBBBBB; font: normal 22px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 32px;"} + %h1{style: "color: #BBBBBB; font: normal 20px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 32px;"} GITLAB - if @project - → #{@project.name_with_namespace} + \/ #{@project.name_with_namespace} %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 diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index 709807456c8..e00f96a7723 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -14,9 +14,9 @@ - if @project.repo_exists? - if can? current_user, :download_code, @project = nav_link(controller: %w(tree blob blame)) do - = link_to 'Files', project_tree_path(@project, @ref || @project.root_ref) + = link_to 'Files', project_tree_path(@project, @ref || @repository.root_ref) = nav_link(controller: %w(commit commits compare repositories protected_branches)) do - = link_to "Commits", project_commits_path(@project, @ref || @project.root_ref) + = link_to "Commits", project_commits_path(@project, @ref || @repository.root_ref) = nav_link(path: 'projects#graph') do = link_to "Network", graph_project_path(@project) diff --git a/app/views/merge_requests/_filter.html.haml b/app/views/merge_requests/_filter.html.haml new file mode 100644 index 00000000000..86148fbcfee --- /dev/null +++ b/app/views/merge_requests/_filter.html.haml @@ -0,0 +1,20 @@ += form_tag project_issues_path(@project), method: 'get' do + %fieldset + %ul.nav.nav-pills.nav-stacked + %li{class: ("active" if (params[:f] == 'open' || !params[:f]))} + = link_to project_merge_requests_path(@project, f: 'open', milestone_id: params[:milestone_id]) do + Open + %li{class: ("active" if params[:f] == "closed")} + = link_to project_merge_requests_path(@project, f: "closed", milestone_id: params[:milestone_id]) do + Closed + %li{class: ("active" if params[:f] == 'assigned-to-me')} + = link_to project_merge_requests_path(@project, f: 'assigned-to-me', milestone_id: params[:milestone_id]) do + Assigned To Me + %li{class: ("active" if params[:f] == 'all')} + = link_to project_merge_requests_path(@project, f: 'all', milestone_id: params[:milestone_id]) do + All + + %fieldset + %hr + = link_to "Reset", project_merge_requests_path(@project), class: 'btn right' + diff --git a/app/views/merge_requests/_form.html.haml b/app/views/merge_requests/_form.html.haml index 9606e2e53b3..9a4f0617a3a 100644 --- a/app/views/merge_requests/_form.html.haml +++ b/app/views/merge_requests/_form.html.haml @@ -1,54 +1,59 @@ -= form_for [@project, @merge_request], html: { class: "new_merge_request form-horizontal" } do |f| += form_for [@project, @merge_request], html: { class: "#{controller.action_name}-merge-request form-horizontal" } do |f| -if @merge_request.errors.any? .alert-message.block-message.error %ul - @merge_request.errors.full_messages.each do |msg| %li= msg - %h4.cdark 1. Select Branches - %br + %fieldset + %legend 1. Select Branches - .row - .span5 - .mr_branch_box - %h5 From (Head Branch) - .body - .padded= f.select(:source_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span4'}) - .mr_source_commit + .row + .span5 + .mr_branch_box + %h5.cgray From (Head Branch) + .body + .padded= f.select(:source_branch, @repository.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span4'}) + .mr_source_commit - .span2 - %center= image_tag "merge.png", class: 'mr_direction_tip' - .span5 - .mr_branch_box - %h5 To (Base Branch) - .body - .padded= f.select(:target_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span4'}) - .mr_target_commit + .span2 + %center= image_tag "merge.png", class: 'mr_direction_tip' + .span5 + .mr_branch_box + %h5.cgray To (Base Branch) + .body + .padded= f.select(:target_branch, @repository.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span4'}) + .mr_target_commit - %h4.cdark 2. Fill info + %fieldset + %legend 2. Fill info - .clearfix - .merge_requests_form_box - .top_box_content - = f.label :title do - %strong= "Title *" - .input= f.text_field :title, class: "input-xxlarge pad js-gfm-input", maxlength: 255, rows: 5, required: true - .merge_requests_middle_box - .merge_requests_assignee - = 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" }, {class: 'chosen span3'}) - .merge_requests_milestone - = 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" }, {class: 'chosen'}) + .ui-box.ui-box-show + .ui-box-head + .clearfix + = f.label :title do + %strong= "Title *" + .input= f.text_field :title, class: "input-xxlarge pad js-gfm-input", maxlength: 255, rows: 5, required: true + .ui-box-body + .clearfix + .left + = 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" }, {class: 'chosen span3'}) + .left + = 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" }, {class: 'chosen'}) .control-group .form-actions - = f.submit 'Save', class: "btn save-btn" + - if @merge_request.new_record? + = f.submit 'Submit merge request', class: "btn success" + -else + = f.submit 'Save changes', class: "save-btn btn" - if @merge_request.new_record? = link_to project_merge_requests_path(@project), class: "btn cancel-btn" do Cancel @@ -59,8 +64,9 @@ :javascript $(function(){ disableButtonIfEmptyField("#merge_request_title", ".save-btn"); - var source_branch = $("#merge_request_source_branch"); - var target_branch = $("#merge_request_target_branch"); + + var source_branch = $("#merge_request_source_branch") + , target_branch = $("#merge_request_target_branch"); $.get("#{branch_from_project_merge_requests_path(@project)}", {ref: source_branch.val() }); $.get("#{branch_to_project_merge_requests_path(@project)}", {ref: target_branch.val() }); diff --git a/app/views/merge_requests/_show.html.haml b/app/views/merge_requests/_show.html.haml index 8285a56d184..cefd33c0cdf 100644 --- a/app/views/merge_requests/_show.html.haml +++ b/app/views/merge_requests/_show.html.haml @@ -1,31 +1,33 @@ -= render "merge_requests/show/mr_title" -= render "merge_requests/show/how_to_merge" -= render "merge_requests/show/mr_box" -= render "merge_requests/show/mr_accept" -- if @project.gitlab_ci? - = render "merge_requests/show/mr_ci" -= render "merge_requests/show/commits" +.merge-request + = render "merge_requests/show/mr_title" + = render "merge_requests/show/how_to_merge" + = render "merge_requests/show/mr_box" + = render "merge_requests/show/mr_accept" + - if @project.gitlab_ci? + = render "merge_requests/show/mr_ci" + = render "merge_requests/show/commits" -- if @commits.present? - %ul.nav.nav-tabs.mr_nav_tabs - %li - = link_to "#notes", title: "Discussion", "data-url" => project_merge_request_path(@project, @merge_request), class: "merge-notes-tab tab" do - %i.icon-comments - Discussion - %li - = link_to "#diffs", title: "Diff", "data-url" => diffs_project_merge_request_path(@project, @merge_request), class: "merge-diffs-tab tab" do - %i.icon-list-alt - Diff + - if @commits.present? + %ul.nav.nav-tabs + %li.notes-tab{data: {action: 'notes'}} + = link_to project_merge_request_path(@project, @merge_request) do + %i.icon-comment + Discussion + %li.diffs-tab{data: {action: 'diffs'}} + = link_to diffs_project_merge_request_path(@project, @merge_request) do + %i.icon-list-alt + Diff -.merge_request_notes.voting_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" } - = render "notes/notes_with_form" -.merge-request-diffs - = render "merge_requests/show/diffs" if @diffs -.status + .notes.tab-content.voting_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" } + = render "notes/notes_with_form" + .diffs.tab-content + = render "merge_requests/show/diffs" if @diffs + .status :javascript + var merge_request; $(function(){ - MergeRequest.init({ + merge_request = new MergeRequest({ url_to_automerge_check: "#{automerge_check_project_merge_request_path(@project, @merge_request)}", check_enable: #{@merge_request.state == MergeRequest::UNCHECKED ? "true" : "false"}, url_to_ci_check: "#{ci_status_project_merge_request_path(@project, @merge_request)}", @@ -33,10 +35,5 @@ current_state: "#{@merge_request.human_state}", action: "#{controller.action_name}" }); - - $(".edit_merge_request").live("ajax:beforeSend", function() { - $('.can_be_merged').hide(); - $('.merge_in_progress').show(); - }) - }) + }); diff --git a/app/views/merge_requests/automerge.js.haml b/app/views/merge_requests/automerge.js.haml index 93e184455af..e01ff662e7d 100644 --- a/app/views/merge_requests/automerge.js.haml +++ b/app/views/merge_requests/automerge.js.haml @@ -3,5 +3,5 @@ location.reload(); -else :plain - MergeRequest.already_cannot_be_merged() + merge_request.alreadyOrCannotBeMerged() diff --git a/app/views/merge_requests/commits.js.haml b/app/views/merge_requests/commits.js.haml index 76322bdb210..923b1ea032f 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 c758cf69015..266892c01ef 100644 --- a/app/views/merge_requests/diffs.js.haml +++ b/app/views/merge_requests/diffs.js.haml @@ -1,3 +1,2 @@ :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 5b234bfbe02..43651a5ca15 100644 --- a/app/views/merge_requests/index.html.haml +++ b/app/views/merge_requests/index.html.haml @@ -1,48 +1,35 @@ +- if can? current_user, :write_issue, @project + = link_to new_project_merge_request_path(@project), class: "right btn primary", title: "New Merge Request" do + %i.icon-plus + New Merge Request %h3.page_title Merge Requests - - if can? current_user, :write_issue, @project - = link_to new_project_merge_request_path(@project), class: "right btn", title: "New Merge Request" do - New Merge Request %br -.ui-box - .title - .left - %ul.nav.nav-pills - %li{class: ("active" if (params[:f] == 'open' || !params[:f]))} - = link_to project_merge_requests_path(@project, f: 'open', milestone_id: params[:milestone_id]) do - Open - %li{class: ("active" if params[:f] == "closed")} - = link_to project_merge_requests_path(@project, f: "closed", milestone_id: params[:milestone_id]) do - Closed - %li{class: ("active" if params[:f] == 'assigned-to-me')} - = link_to project_merge_requests_path(@project, f: 'assigned-to-me', milestone_id: params[:milestone_id]) do - To Me - %li{class: ("active" if params[:f] == 'all')} - = link_to project_merge_requests_path(@project, f: 'all', milestone_id: params[:milestone_id]) do - All - .right - = form_tag project_merge_requests_path(@project), id: "merge_requests_search_form", method: :get, class: :right do - = 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 +.row + .span3 + = render 'filter', entity: 'issue' + .span9 + .ui-box + .title + = form_tag project_merge_requests_path(@project), id: "merge_requests_search_form", method: :get, class: :left do + = 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.well-list - = render @merge_requests - - if @merge_requests.blank? - %li - %h4.nothing_here_message Nothing to show here - - if @merge_requests.present? - %li.bottom - .row - .span7= paginate @merge_requests, theme: "gitlab" - .span4.right - %span.cgray.right #{@merge_requests.total_count} merge requests for this filter + %ul.well-list + = render @merge_requests + - if @merge_requests.blank? + %li + %h4.nothing_here_message Nothing to show here + - if @merge_requests.present? + %li.bottom + .left= paginate @merge_requests, theme: "gitlab" + .right + %span.cgray.right #{@merge_requests.total_count} merge requests for this filter :javascript - $(function() { - merge_requestsPage(); - }) + $(merge_requestsPage); diff --git a/app/views/merge_requests/show.js.haml b/app/views/merge_requests/show.js.haml index 7f423c786de..2ce6eb63290 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_with_form")}"); + merge_request.$(".notes").html("#{escape_javascript(render "notes/notes_with_form")}"); diff --git a/app/views/merge_requests/show/_commits.html.haml b/app/views/merge_requests/show/_commits.html.haml index 796922776d9..5e27b6dc25a 100644 --- a/app/views/merge_requests/show/_commits.html.haml +++ b/app/views/merge_requests/show/_commits.html.haml @@ -1,18 +1,18 @@ - if @commits.present? .ui-box - %h5 + %h5.title %i.icon-list Commits (#{@commits.count}) - .merge-request-commits + .commits - if @commits.count > 8 - %ul.first_mr_commits.well-list + %ul.first-commits.well-list - @commits.first(8).each do |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.well-list + %a.show-all-commits Click here to show all + %ul.all-commits.hide.well-list - @commits.each do |commit| = render "commits/commit", commit: commit diff --git a/app/views/merge_requests/show/_mr_accept.html.haml b/app/views/merge_requests/show/_mr_accept.html.haml index f24228856ff..128ffe76782 100644 --- a/app/views/merge_requests/show/_mr_accept.html.haml +++ b/app/views/merge_requests/show/_mr_accept.html.haml @@ -9,19 +9,24 @@ %span = 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 - + 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" for instructions .accept_group - = f.submit "Accept Merge Request", class: "btn small success accept_merge_request" - - unless @project.root_ref? @merge_request.source_branch + = f.submit "Accept Merge Request", class: "btn 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.no_satellite{style: "display:none"} + .alert.alert-error + %span + %strong This repository does not have satellite. Ask administrator to fix this issue .automerge_widget.cannot_be_merged{style: "display:none"} .alert.alert-info @@ -40,6 +45,6 @@ .alert.alert-info %strong This merge request already can not be merged. Try to reload page. - .merge_in_progress.hide + .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 cd33732d191..644d7fcc58e 100644 --- a/app/views/merge_requests/show/_mr_box.html.haml +++ b/app/views/merge_requests/show/_mr_box.html.haml @@ -1,5 +1,5 @@ -.main_box - .top_box_content +.ui-box.ui-box-show + .ui-box-head %h4.box-title - if @merge_request.merged .error.status_info @@ -9,7 +9,7 @@ .error.status_info Closed = gfm escape_once(@merge_request.title) - .middle_box_content + .ui-box-body %div %cite.cgray Created at #{@merge_request.created_at.stamp("Aug 21, 2011")} by #{link_to_member(@project, @merge_request.author)} @@ -22,7 +22,7 @@ - if @merge_request.closed - .bottom_box_content + .ui-box-bottom - if @merge_request.merged? %span Merged by #{link_to_member(@project, @merge_request.merge_event.author)} diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml index c4975c72ef2..fc7ae51f184 100644 --- a/app/views/milestones/show.html.haml +++ b/app/views/milestones/show.html.haml @@ -27,8 +27,8 @@ %span All issues for this milestone are closed. You may close milestone now. = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {closed: true }), method: :put, class: "btn small danger" -.main_box - .top_box_content +.ui-box.ui-box-show + .ui-box-head %h4.box-title - if @milestone.closed .error.status_info Closed @@ -37,52 +37,47 @@ = gfm escape_once(@milestone.title) - .middle_box_content - %h5 + .ui-box-body + %p Progress: - %small - #{@milestone.closed_items_count} closed - – - #{@milestone.open_items_count} open + #{@milestone.closed_items_count} closed + – + #{@milestone.open_items_count} open %span.right= @milestone.expires_at .progress.progress-info .bar{style: "width: #{@milestone.percent_complete}%;"} - if @milestone.description.present? - .bottom_box_content + .ui-box-bottom = preserve do = markdown @milestone.description .row .span6 - %table.milestone-issue-filter - %thead - %tr - %th - %ul.nav.nav-pills - %li.active= link_to('Open Issues', '#') - %li=link_to('All Issues', '#') - - @issues.each do |issue| - %tr{data: {closed: issue.closed}} - %td + .ui-box.milestone-issue-filter + .title + %ul.nav.nav-pills + %li.active= link_to('Open Issues', '#') + %li=link_to('All Issues', '#') + %ul.well-list + - @issues.each do |issue| + %li{data: {closed: issue.closed}} = link_to [@project, issue] do %span.badge.badge-info ##{issue.id} – = link_to_gfm truncate(issue.title, length: 60), [@project, issue] .span6 - %table.milestone-merge-requests-filter - %thead - %tr - %th - %ul.nav.nav-pills - %li.active= link_to('Open Merge Requests', '#') - %li=link_to('All Merge Requests', '#') - - @merge_requests.each do |merge_request| - %tr{data: {closed: merge_request.closed}} - %td + .ui-box.milestone-merge-requests-filter + .title + %ul.nav.nav-pills + %li.active= link_to('Open Merge Requests', '#') + %li=link_to('All Merge Requests', '#') + %ul.well-list + - @merge_requests.each do |merge_request| + %li{data: {closed: merge_request.closed}} = link_to [@project, merge_request] do %span.badge.badge-info ##{merge_request.id} – diff --git a/app/views/notes/_note.html.haml b/app/views/notes/_note.html.haml index 8881cf5a847..6f7eea9827f 100644 --- a/app/views/notes/_note.html.haml +++ b/app/views/notes/_note.html.haml @@ -28,6 +28,8 @@ = preserve do = markdown(note.note) - if note.attachment.url + - if note.attachment.image? + = image_tag note.attachment.url, class: 'thumbnail span4' .attachment.right = link_to note.attachment.url, target: "_blank" do %i.icon-attachment diff --git a/app/views/notify/issue_status_changed_email.html.haml b/app/views/notify/issue_status_changed_email.html.haml index c433e80c9e5..27168eef742 100644 --- a/app/views/notify/issue_status_changed_email.html.haml +++ b/app/views/notify/issue_status_changed_email.html.haml @@ -1,8 +1,8 @@ %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;"} + %td{width: "21"} + %td %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} = "Issue was #{@issue_status} by #{@updated_by.name}" %td{style: "font-size: 1px; line-height: 1px;", width: "21"} diff --git a/app/views/notify/new_issue_email.html.haml b/app/views/notify/new_issue_email.html.haml index fba4b865487..3cb5351319e 100644 --- a/app/views/notify/new_issue_email.html.haml +++ b/app/views/notify/new_issue_email.html.haml @@ -1,13 +1,13 @@ %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;"} + %td{width: "21"} + %td %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{width: "21"} %tr - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{width: "21"} %td{align: "left", style: "padding: 20px 0 0;"} %p{style: "color:#646464 !important; line-height: 26px; font-size: 16px; font-family: Helvetica, Arial, sans-serif; "} = "Issue ##{@issue.id}" diff --git a/app/views/notify/new_merge_request_email.html.haml b/app/views/notify/new_merge_request_email.html.haml index 9819767011e..990d4d2aa87 100644 --- a/app/views/notify/new_merge_request_email.html.haml +++ b/app/views/notify/new_merge_request_email.html.haml @@ -14,6 +14,6 @@ %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; "} - Asignee: #{@merge_request.author_name} → #{@merge_request.assignee_name} + Assignee: #{@merge_request.author_name} → #{@merge_request.assignee_name} %td diff --git a/app/views/notify/note_merge_request_email.html.haml b/app/views/notify/note_merge_request_email.html.haml index 764cd094b76..3857f2f0318 100644 --- a/app/views/notify/note_merge_request_email.html.haml +++ b/app/views/notify/note_merge_request_email.html.haml @@ -1,23 +1,27 @@ %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 !#{@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"} + %td{width: "21"} + %td + %h2{style: "color:#646464; font-weight: normal;"} + - if @note.for_diff_line? + = link_to "New comment on diff", diffs_project_merge_request_url(@merge_request.project, @merge_request, anchor: "note_#{@note.id}") + - else + = link_to "New comment", project_merge_request_url(@merge_request.project, @merge_request, anchor: "note_#{@note.id}") + for Merge Request ##{@merge_request.id} + %cite "#{truncate(@merge_request.title, length: 20)}" + %td{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{width: "21"} + %td + %p + %strong #{@note.author_name} left next message: %br %table{border: "0", cellpadding: "0", cellspacing: "0", width: "558"} %tr %td{valign: "top"} - %div{ style: "background:#f5f5f5; padding:20px;border:1px solid #ddd" } + %div{ style: "background:#f5f5f5; padding:10px 20px;border:1px solid #ddd" } = markdown(@note.note) - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} + %td{width: "21"} diff --git a/app/views/notify/reassigned_issue_email.html.haml b/app/views/notify/reassigned_issue_email.html.haml index 31a5d23242c..bc2d6f7078b 100644 --- a/app/views/notify/reassigned_issue_email.html.haml +++ b/app/views/notify/reassigned_issue_email.html.haml @@ -2,7 +2,7 @@ %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;"} + %td %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: 30), project_issue_url(@issue.project, @issue) diff --git a/app/views/profiles/account.html.haml b/app/views/profiles/account.html.haml index 3c290948d6c..522e45e637a 100644 --- a/app/views/profiles/account.html.haml +++ b/app/views/profiles/account.html.haml @@ -69,7 +69,7 @@ %i.icon-ok Saved %span.update-failed.cred.hide - %i.icon-ok + %i.icon-remove Failed %ul.cred %li It will change web url for personal projects. diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 934c1fdf7c4..64f931ca887 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -64,7 +64,7 @@ %legend Personal projects: %small.right - %span= current_user.my_own_projects.count + %span= current_user.personal_projects.count of %span= current_user.projects_limit .padded diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index 7044d1f20be..c8eacdc2a46 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -15,13 +15,13 @@ = f.label :path do Repository .controls - = text_field_tag :ppath, @project.path_to_repo, class: "xxlarge", readonly: true + = text_field_tag :ppath, @repository.path_to_repo, class: "xxlarge", readonly: true - - unless @project.heads.empty? + - unless @repository.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, @repository.heads.map(&:name), {}, style: "width:210px;") %fieldset.features %legend Features: diff --git a/app/views/projects/_new_form.html.haml b/app/views/projects/_new_form.html.haml index 2ef29cb0c65..2391c750bc8 100644 --- a/app/views/projects/_new_form.html.haml +++ b/app/views/projects/_new_form.html.haml @@ -7,7 +7,7 @@ Project name is .input = f.text_field :name, placeholder: "Example Project", class: "xxlarge" - = f.submit 'Create project', class: "btn primary project-submit" + = f.submit 'Create project', class: "btn success project-submit" - if current_user.several_namespaces? .clearfix diff --git a/app/views/protected_branches/index.html.haml b/app/views/protected_branches/index.html.haml index f408fd16c2c..c1ecceda435 100644 --- a/app/views/protected_branches/index.html.haml +++ b/app/views/protected_branches/index.html.haml @@ -1,51 +1,54 @@ -= render "repositories/branches_head" += render "commits/head" +.row + .span3 + = render "repositories/filter" + .span9 + .alert + %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"} -.alert - %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"} + - if can? current_user, :admin_project, @project + = form_for [@project, @protected_branch] do |f| + -if @protected_branch.errors.any? + .alert-message.block-message.error + %ul + - @protected_branch.errors.full_messages.each do |msg| + %li= msg -- if can? current_user, :admin_project, @project - = form_for [@project, @protected_branch] do |f| - -if @protected_branch.errors.any? - .alert-message.block-message.error - %ul - - @protected_branch.errors.full_messages.each do |msg| - %li= msg + .entry.clearfix + = f.label :name, "Branch" + .span3 + = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , {include_blank: "Select branch"}, {class: "chosen span3"}) + + = f.submit 'Protect', class: "primary btn" - .entry.clearfix - = f.label :name, "Branch" - .span3 - = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , {include_blank: "Select branch"}, {class: "chosen span3"}) - - = f.submit 'Protect', class: "primary btn" - -- unless @branches.empty? - %table - %thead - %tr - %th Name - %th Last commit - %th - %tbody - - @branches.each do |branch| - %tr - %td - = link_to project_commits_path(@project, branch.name) do - %strong= branch.name - - if branch.name == @project.root_ref - %span.label default - %td - - if branch.commit - = 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 - - else - (branch was removed from repository) - %td - - if can? current_user, :admin_project, @project - = link_to 'Unprotect', [@project, branch], confirm: 'Are you sure?', method: :delete, class: "danger btn small" + - unless @branches.empty? + %table + %thead + %tr + %th Name + %th Last commit + %th + %tbody + - @branches.each do |branch| + %tr + %td + = link_to project_commits_path(@project, branch.name) do + %strong= branch.name + - if @project.root_ref?(branch.name) + %span.label default + %td + - if branch.commit + = 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 + - else + (branch was removed from repository) + %td + - if can? current_user, :admin_project, @project + = link_to 'Unprotect', [@project, branch], confirm: 'Are you sure?', method: :delete, class: "danger btn small" diff --git a/app/views/repositories/_branch.html.haml b/app/views/repositories/_branch.html.haml index 2728b100ff6..a6faa5fd633 100644 --- a/app/views/repositories/_branch.html.haml +++ b/app/views/repositories/_branch.html.haml @@ -8,7 +8,7 @@ - else %i.icon-unlock %strong= truncate(branch.name, length: 60) - - if branch.name == @project.root_ref + - if branch.name == @repository.root_ref %span.label default %td = link_to project_commit_path(@project, commit.id), class: 'commit_short_id' do @@ -22,6 +22,6 @@ %td - if can? current_user, :download_code, @project = link_to archive_project_repository_path(@project, ref: branch.name) do - %i.icon-download + %i.icon-download-alt Download diff --git a/app/views/repositories/_feed.html.haml b/app/views/repositories/_feed.html.haml index 496328baca5..44380133718 100644 --- a/app/views/repositories/_feed.html.haml +++ b/app/views/repositories/_feed.html.haml @@ -5,7 +5,7 @@ = link_to project_commits_path(@project, commit.head.name) do %strong = commit.head.name - - if commit.head.name == @project.root_ref + - if @project.root_ref?(commit.head.name) %span.label default %td diff --git a/app/views/repositories/_branches_head.html.haml b/app/views/repositories/_filter.html.haml index 8f3e1ba3f81..e718d48190a 100644 --- a/app/views/repositories/_branches_head.html.haml +++ b/app/views/repositories/_filter.html.haml @@ -1,10 +1,9 @@ -= render "commits/head" -%ul.nav.nav-pills +%ul.nav.nav-pills.nav-stacked = nav_link(path: 'repositories#show') do = link_to 'Recent', project_repository_path(@project) = nav_link(path: 'protected_branches#index') do = link_to project_protected_branches_path(@project) do - %i.icon-lock Protected + %i.icon-lock = nav_link(path: 'repositories#branches') do - = link_to 'All', branches_project_repository_path(@project) + = link_to 'All branches', branches_project_repository_path(@project) diff --git a/app/views/repositories/branches.html.haml b/app/views/repositories/branches.html.haml index 4c246c69d7c..14b5082e44e 100644 --- a/app/views/repositories/branches.html.haml +++ b/app/views/repositories/branches.html.haml @@ -1,12 +1,15 @@ -= render "repositories/branches_head" -- unless @branches.empty? - %table - %thead - %tr - %th Name - %th Last commit - %th - - %tbody - - @branches.each do |branch| - = render "repositories/branch", branch: branch += render "commits/head" +.row + .span3 + = render "filter" + .span9 + - unless @branches.empty? + %table + %thead + %tr + %th Name + %th Last commit + %th + %tbody + - @branches.each do |branch| + = render "repositories/branch", branch: branch diff --git a/app/views/repositories/show.html.haml b/app/views/repositories/show.html.haml index fd0abac8414..e58e16f8bf1 100644 --- a/app/views/repositories/show.html.haml +++ b/app/views/repositories/show.html.haml @@ -1,11 +1,14 @@ -= render "branches_head" - -%table - %thead - %tr - %th Name - %th Last commit - %th - - @activities.each do |update| - = render "repositories/branch", branch: update.head += render "commits/head" +.row + .span3 + = render "filter" + .span9 + %table + %thead + %tr + %th Name + %th Last commit + %th + - @activities.each do |update| + = render "repositories/branch", branch: update.head diff --git a/app/views/repositories/stats.html.haml b/app/views/repositories/stats.html.haml index a93814a4777..bdf047f1e98 100644 --- a/app/views/repositories/stats.html.haml +++ b/app/views/repositories/stats.html.haml @@ -7,7 +7,7 @@ %b Total commits: %span= @stats.commits_count %p - %b Total files in #{@project.root_ref}: + %b Total files in #{@repository.root_ref}: %span= @stats.files_count %p %b Authors: diff --git a/app/views/repositories/tags.html.haml b/app/views/repositories/tags.html.haml index 193cb2e30f2..d4b8bbe10d4 100644 --- a/app/views/repositories/tags.html.haml +++ b/app/views/repositories/tags.html.haml @@ -26,8 +26,14 @@ %td - if can? current_user, :download_code, @project = link_to archive_project_repository_path(@project, ref: tag.name) do - %i.icon-download + %i.icon-download-alt Download - else - %h3 No tags + %h3.nothing_here_message + Repository has no tags yet. + %br + %small + Use git tag command to add a new one: + %br + %span.monospace git tag -a v1.4 -m 'version 1.4' diff --git a/app/views/search/_result.html.haml b/app/views/search/_result.html.haml index 8b137891791..79bed4f737c 100644 --- a/app/views/search/_result.html.haml +++ b/app/views/search/_result.html.haml @@ -1 +1,85 @@ +%br +%h3.page_title + Search results + %span.cgray (#{@projects.count + @merge_requests.count + @issues.count + @wiki_pages.count}) +%hr +.search_results + .row + .span6 + %table + %thead + %tr + %th Projects + %tbody + - @projects.each do |project| + %tr + %td + = link_to project do + %strong.term= project.name_with_namespace + %small.cgray + last activity at + = project.last_activity_date.stamp("Aug 25, 2011") + - if @projects.blank? + %tr + %td + %h4.nothing_here_message No Projects + %br + %table + %thead + %tr + %th Merge Requests + %tbody + - @merge_requests.each do |merge_request| + %tr + %td + = link_to [merge_request.project, merge_request] do + %span.badge.badge-info ##{merge_request.id} + – + %strong.term= truncate merge_request.title, length: 50 + %strong.right + %span.label= merge_request.project.name + - if @merge_requests.blank? + %tr + %td + %h4.nothing_here_message No Merge Requests + .span6 + %table + %thead + %tr + %th Issues + %tbody + - @issues.each do |issue| + %tr + %td + = link_to [issue.project, issue] do + %span.badge.badge-info ##{issue.id} + – + %strong.term= truncate issue.title, length: 40 + %strong.right + %span.label= issue.project.name + - if @issues.blank? + %tr + %td + %h4.nothing_here_message No Issues + .span6 + %table + %thead + %tr + %th Wiki + %tbody + - @wiki_pages.each do |wiki_page| + %tr + %td + = link_to project_wiki_path(wiki_page.project, wiki_page) do + %strong.term= truncate wiki_page.title, length: 40 + %strong.right + %span.label= wiki_page.project.name + - if @wiki_pages.blank? + %tr + %td + %h4.nothing_here_message No wiki pages +:javascript + $(function() { + $(".search_results .term").highlight("#{escape_javascript(params[:search])}"); + }) diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml index 8448193deb9..aa0d6d700d9 100644 --- a/app/views/search/show.html.haml +++ b/app/views/search/show.html.haml @@ -6,87 +6,4 @@ = search_field_tag :search, params[:search], placeholder: "issue 143", class: "input-xxlarge search-text-input", id: "dashboard_search" = submit_tag 'Search', class: "btn primary wide" - if params[:search].present? - %br - %h3 - Search results - %small (#{@projects.count + @merge_requests.count + @issues.count + @wiki_pages.count}) - %hr - .search_results - .row - .span6 - %table - %thead - %tr - %th Projects - %tbody - - @projects.each do |project| - %tr - %td - = link_to project do - %strong.term= project.name_with_namespace - %small.cgray - last activity at - = project.last_activity_date.stamp("Aug 25, 2011") - - if @projects.blank? - %tr - %td - %h4.nothing_here_message No Projects - %br - %table - %thead - %tr - %th Merge Requests - %tbody - - @merge_requests.each do |merge_request| - %tr - %td - = link_to [merge_request.project, merge_request] do - %span.badge.badge-info ##{merge_request.id} - – - %strong.term= truncate merge_request.title, length: 50 - %strong.right - %span.label= merge_request.project.name - - if @merge_requests.blank? - %tr - %td - %h4.nothing_here_message No Merge Requests - .span6 - %table - %thead - %tr - %th Issues - %tbody - - @issues.each do |issue| - %tr - %td - = link_to [issue.project, issue] do - %span.badge.badge-info ##{issue.id} - – - %strong.term= truncate issue.title, length: 40 - %strong.right - %span.label= issue.project.name - - if @issues.blank? - %tr - %td - %h4.nothing_here_message No Issues - .span6 - %table - %thead - %tr - %th Wiki - %tbody - - @wiki_pages.each do |wiki_page| - %tr - %td - = link_to project_wiki_path(wiki_page.project, wiki_page) do - %strong.term= truncate wiki_page.title, length: 40 - %strong.right - %span.label= wiki_page.project.name - - if @wiki_pages.blank? - %tr - %td - %h4.nothing_here_message No wiki pages - :javascript - $(function() { - $(".search_results .term").highlight("#{params[:search]}"); - }) + = render 'search/result' diff --git a/app/views/team_members/_form.html.haml b/app/views/team_members/_form.html.haml index e5d9a4a4b5e..a963e462a78 100644 --- a/app/views/team_members/_form.html.haml +++ b/app/views/team_members/_form.html.haml @@ -11,7 +11,7 @@ %h6 1. Choose people you want in the team .clearfix = f.label :user_ids, "People" - .input= select_tag(:user_ids, options_from_collection_for_select(User.active.not_in_project(@project).all, :id, :name), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true}) + .input= select_tag(:user_ids, options_from_collection_for_select(User.active.not_in_project(@project).alphabetically, :id, :name), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true}) %h6 2. Set access level for them .clearfix diff --git a/app/views/team_members/_team.html.haml b/app/views/team_members/_team.html.haml index 462e75af183..365d9b65942 100644 --- a/app/views/team_members/_team.html.haml +++ b/app/views/team_members/_team.html.haml @@ -1,6 +1,6 @@ - grouper_project_members(@project).each do |access, members| .ui-box - %h5 + %h5.title = Project.access_options.key(access).pluralize %small= members.size %ul.well-list diff --git a/app/views/team_members/import.html.haml b/app/views/team_members/import.html.haml index 34f7fb03288..de82f416248 100644 --- a/app/views/team_members/import.html.haml +++ b/app/views/team_members/import.html.haml @@ -9,7 +9,7 @@ %p.slead Choose project you want to use as team source: .padded = label_tag :source_project_id, "Project" - .input= select_tag(:source_project_id, options_from_collection_for_select(current_user.projects, :id, :name), prompt: "Select project", class: "chosen xxlarge", required: true) + .input= select_tag(:source_project_id, options_from_collection_for_select(current_user.authorized_projects, :id, :name_with_namespace), prompt: "Select project", class: "chosen xxlarge", required: true) .actions = submit_tag 'Import', class: "btn save-btn" diff --git a/app/views/team_members/show.html.haml b/app/views/team_members/show.html.haml index af9a6e6b92d..4008e8bd23e 100644 --- a/app/views/team_members/show.html.haml +++ b/app/views/team_members/show.html.haml @@ -8,8 +8,7 @@ = image_tag gravatar_icon(user.email, 60), class: "borders" %h3.page_title = user.name - %small - = user.email + %small (@#{user.username}) %hr .back_link diff --git a/app/views/tree/_tree.html.haml b/app/views/tree/_tree.html.haml index a632bb3b0d7..c2842959510 100644 --- a/app/views/tree/_tree.html.haml +++ b/app/views/tree/_tree.html.haml @@ -3,9 +3,13 @@ %span.arrow = link_to project_tree_path(@project, @ref) do = @project.name - - tree.breadcrumbs(6) do |link| + - tree.breadcrumbs(6) do |title, path| \/ - %li= link + %li + - if path + = link_to truncate(title, length: 40), project_tree_path(@project, path) + - else + = link_to title, '#' .clear %div.tree_progress @@ -26,7 +30,7 @@ %tr.tree-item %td.tree-item-file-name = image_tag "file_empty.png", size: '16x16' - = link_to "..", tree.up_dir_path + = link_to "..", project_tree_path(@project, tree.up_dir_path) %td %td %td diff --git a/app/views/tree/blob/_download.html.haml b/app/views/tree/blob/_download.html.haml index c307622995b..864c209db76 100644 --- a/app/views/tree/blob/_download.html.haml +++ b/app/views/tree/blob/_download.html.haml @@ -2,7 +2,7 @@ %center = link_to project_blob_path(@project, @id) do %div.padded - %br - = image_tag "download.png", width: 64 - %h3 + %h4 + %i.icon-download-alt + %br Download (#{number_to_human_size blob.size}) diff --git a/app/views/wikis/_form.html.haml b/app/views/wikis/_form.html.haml index 83b16b138d3..9eb2a571fe5 100644 --- a/app/views/wikis/_form.html.haml +++ b/app/views/wikis/_form.html.haml @@ -6,12 +6,12 @@ - @wiki.errors.full_messages.each do |msg| %li= msg - .main_box - .top_box_content + .ui-box.ui-box-show + .ui-box-head = f.label :title .input= f.text_field :title, class: 'span8' = f.hidden_field :slug - .middle_box_content + .ui-box-body .input %span.cgray Wiki content is parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}. @@ -19,7 +19,7 @@ %code [Link Title](page-slug) \. - .bottom_box_content + .ui-box-bottom = f.label :content .input= f.text_area :content, class: 'span8 js-gfm-input' .actions diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index 1414ed490c9..e74379a65dd 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -1,7 +1,9 @@ class PostReceive - @queue = :post_receive + include Sidekiq::Worker - def self.perform(repo_path, oldrev, newrev, ref, identifier) + sidekiq_options queue: :post_receive + + def perform(repo_path, oldrev, newrev, ref, identifier) repo_path.gsub!(Gitlab.config.gitolite.repos_path.to_s, "") repo_path.gsub!(/.git$/, "") repo_path.gsub!(/^\//, "") @@ -11,7 +13,7 @@ class PostReceive # Ignore push from non-gitlab users user = if identifier.eql? Gitlab.config.gitolite.admin_key - email = project.commit(newrev).author.email rescue nil + email = project.repository.commit(newrev).author.email rescue nil User.find_by_email(email) if email elsif /^[A-Z0-9._%a-z\-]+@(?:[A-Z0-9a-z\-]+\.)+[A-Za-z]{2,4}$/.match(identifier) User.find_by_email(identifier) diff --git a/app/workers/system_hook_worker.rb b/app/workers/system_hook_worker.rb index ca154136b97..3ebc62b7e7a 100644 --- a/app/workers/system_hook_worker.rb +++ b/app/workers/system_hook_worker.rb @@ -1,7 +1,9 @@ class SystemHookWorker - @queue = :system_hook + include Sidekiq::Worker - def self.perform(hook_id, data) + sidekiq_options queue: :system_hook + + def perform(hook_id, data) SystemHook.find(hook_id).execute data end end |