diff --git a/app/assets/javascripts/merge_requests.js b/app/assets/javascripts/merge_requests.js index 0ab6f6e2..cc6b0771 100644 --- a/app/assets/javascripts/merge_requests.js +++ b/app/assets/javascripts/merge_requests.js @@ -115,4 +115,15 @@ var MergeRequest = { $(".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/milestones.js.coffee b/app/assets/javascripts/milestones.js.coffee index 13aba860..e40a69eb 100644 --- a/app/assets/javascripts/milestones.js.coffee +++ b/app/assets/javascripts/milestones.js.coffee @@ -5,3 +5,10 @@ $ -> $('.milestone-issue-filter li').toggleClass('active') $('.milestone-issue-filter tr[data-closed]').toggleClass('hide') false + + $('.milestone-merge-requests-filter tr[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') + false diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index 8ebbb53b..843b683f 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -670,3 +670,16 @@ pre { padding:0; } } + +.milestone .progress { + margin-bottom: 0; + margin-top:4px; +} + +.float-link { + float:left; + margin-right:15px; + .s16 { + margin-right:5px; + } +} diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss index c932f0fc..fc9ad472 100644 --- a/app/assets/stylesheets/sections/merge_requests.scss +++ b/app/assets/stylesheets/sections/merge_requests.scss @@ -121,3 +121,20 @@ 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/contexts/merge_requests_load_context.rb b/app/contexts/merge_requests_load_context.rb index e7dbdd28..4ec66cd9 100644 --- a/app/contexts/merge_requests_load_context.rb +++ b/app/contexts/merge_requests_load_context.rb @@ -1,3 +1,5 @@ +# Build collection of Merge Requests +# based on filtering passed via params for @project class MergeRequestsLoadContext < BaseContext def execute type = params[:f] @@ -9,8 +11,21 @@ class MergeRequestsLoadContext < BaseContext when 'closed' then merge_requests.closed when 'assigned-to-me' then merge_requests.opened.assigned(current_user) else merge_requests.opened - end.page(params[:page]).per(20) + end - merge_requests.includes(:author, :project).order("closed, created_at desc") + merge_requests = merge_requests.page(params[:page]).per(20) + merge_requests = merge_requests.includes(:author, :project).order("closed, created_at desc") + + # Filter by specific assignee_id (or lack thereof)? + if params[:assignee_id].present? + merge_requests = merge_requests.where(assignee_id: (params[:assignee_id] == '0' ? nil : params[:assignee_id])) + end + + # Filter by specific milestone_id (or lack thereof)? + if params[:milestone_id].present? + merge_requests = merge_requests.where(milestone_id: (params[:milestone_id] == '0' ? nil : params[:milestone_id])) + end + + merge_requests end end diff --git a/app/controllers/milestones_controller.rb b/app/controllers/milestones_controller.rb index fa202cf4..fadfee2d 100644 --- a/app/controllers/milestones_controller.rb +++ b/app/controllers/milestones_controller.rb @@ -31,7 +31,8 @@ class MilestonesController < ProjectResourceController def show @issues = @milestone.issues - @users = @milestone.participants + @users = UserDecorator.decorate(@milestone.participants) + @merge_requests = @milestone.merge_requests respond_to do |format| format.html diff --git a/app/decorators/user_decorator.rb b/app/decorators/user_decorator.rb new file mode 100644 index 00000000..af9c6a63 --- /dev/null +++ b/app/decorators/user_decorator.rb @@ -0,0 +1,11 @@ +class UserDecorator < ApplicationDecorator + decorates :user + + def avatar_image size = 16 + h.image_tag h.gravatar_icon(self.email, size), class: "avatar #{"s#{size}"}", width: size + end + + def tm_of(project) + project.team_member_by_id(self.id) + end +end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 468ace15..7c302ef4 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -10,5 +10,9 @@ module ProjectsHelper def link_to_project project link_to project.name, project end + + def tm_path team_member + project_team_member_path(@project, team_member) + end end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 9238aa48..c737258d 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -1,14 +1,17 @@ require Rails.root.join("app/models/commit") +require Rails.root.join("app/roles/static_model") class MergeRequest < ActiveRecord::Base include IssueCommonality include Votes - attr_accessible :title, :assignee_id, :closed, :target_branch, :source_branch, + attr_accessible :title, :assignee_id, :closed, :target_branch, :source_branch, :milestone_id, :author_id_of_changes attr_accessor :should_remove_source_branch + belongs_to :milestone + BROKEN_DIFF = "--broken-diff" UNCHECKED = 1 @@ -26,6 +29,10 @@ class MergeRequest < ActiveRecord::Base where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) end + def self.find_all_by_milestone(milestone) + where("milestone_id = :milestone_id", milestone_id: milestone) + end + def human_state states = { CAN_BE_MERGED => "can_be_merged", @@ -212,5 +219,6 @@ end # st_diffs :text(4294967295 # merged :boolean default(FALSE), not null # state :integer default(1), not null +# milestone_id :integer # diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 06c09431..41412a13 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -3,6 +3,7 @@ class Milestone < ActiveRecord::Base belongs_to :project has_many :issues + has_many :merge_requests validates :title, presence: true validates :project, presence: true @@ -15,8 +16,20 @@ class Milestone < ActiveRecord::Base User.where(id: issues.pluck(:assignee_id)) end + def open_items_count + self.issues.opened.count + self.merge_requests.opened.count + end + + def closed_items_count + self.issues.closed.count + self.merge_requests.closed.count + end + + def total_items_count + self.issues.count + self.merge_requests.count + end + def percent_complete - ((self.issues.closed.count * 100) / self.issues.count).abs + ((closed_items_count * 100) / total_items_count).abs rescue ZeroDivisionError 100 end diff --git a/app/views/merge_requests/_form.html.haml b/app/views/merge_requests/_form.html.haml index c420fac2..302e75cf 100644 --- a/app/views/merge_requests/_form.html.haml +++ b/app/views/merge_requests/_form.html.haml @@ -28,16 +28,22 @@ %h4.cdark 2. Fill info .clearfix - .main_box + .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 - .middle_box_content - = f.label :assignee_id do - %i.icon-user - Assign to - .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, {class: 'chosen span3'}) + .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'}) .control-group diff --git a/app/views/merge_requests/_merge_request.html.haml b/app/views/merge_requests/_merge_request.html.haml index 419419d2..ed8ffc0b 100644 --- a/app/views/merge_requests/_merge_request.html.haml +++ b/app/views/merge_requests/_merge_request.html.haml @@ -10,6 +10,10 @@ %span.btn.small.disabled.grouped %i.icon-comment = merge_request.mr_and_commit_notes.count + - if merge_request.milestone_id? + %span.btn.small.disabled.grouped + %i.icon-time + = merge_request.project.milestones.find(merge_request.milestone_id).title %span.btn.small.disabled.grouped = merge_request.source_branch → diff --git a/app/views/merge_requests/index.html.haml b/app/views/merge_requests/index.html.haml index bbf35dc7..7bcb7a81 100644 --- a/app/views/merge_requests/index.html.haml +++ b/app/views/merge_requests/index.html.haml @@ -9,19 +9,26 @@ .ui-box .title - %ul.nav.nav-pills - %li{class: ("active" if (params[:f] == 'open' || !params[:f]))} - = link_to project_merge_requests_path(@project, f: 'open') do - Open - %li{class: ("active" if params[:f] == "closed")} - = link_to project_merge_requests_path(@project, f: "closed") do - Closed - %li{class: ("active" if params[:f] == 'assigned-to-me')} - = link_to project_merge_requests_path(@project, f: 'assigned-to-me') do - To Me - %li{class: ("active" if params[:f] == 'all')} - = link_to project_merge_requests_path(@project, f: 'all') do - All + .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 %ul.unstyled = render @merge_requests @@ -35,3 +42,7 @@ .span4.right %span.cgray.right #{@merge_requests.total_count} merge requests for this filter +:javascript + $(function() { + merge_requestsPage(); + }) diff --git a/app/views/merge_requests/show/_mr_box.html.haml b/app/views/merge_requests/show/_mr_box.html.haml index 89c3110b..26636435 100644 --- a/app/views/merge_requests/show/_mr_box.html.haml +++ b/app/views/merge_requests/show/_mr_box.html.haml @@ -14,9 +14,13 @@ %strong.author= link_to_merge_request_author(@merge_request) - if @merge_request.assignee - %cite.cgray and currently assigned to + %cite.cgray , currently assigned to = image_tag gravatar_icon(@merge_request.assignee_email), width: 16, class: "lil_av" %strong.author= link_to_merge_request_assignee(@merge_request) + - if @merge_request.milestone + - milestone = @merge_request.milestone + %cite.cgray and attached to milestone + %strong= link_to_gfm truncate(milestone.title, length: 20), project_milestone_path(milestone.project, milestone) - if @merge_request.closed diff --git a/app/views/milestones/_milestone.html.haml b/app/views/milestones/_milestone.html.haml index 205b864f..05532c38 100644 --- a/app/views/milestones/_milestone.html.haml +++ b/app/views/milestones/_milestone.html.haml @@ -1,18 +1,21 @@ %li{class: "milestone", id: dom_id(milestone) } .right - - if milestone.issues.any? - %span.btn.small.disabled.grouped= pluralize milestone.issues.count, 'issues' - - if milestone.issues.count > 0 - = link_to 'Browse Issues', project_issues_path(milestone.project, milestone_id: milestone.id), class: "btn small grouped" - if can? current_user, :admin_milestone, milestone.project - = link_to 'Edit', edit_project_milestone_path(milestone.project, milestone), class: "btn small edit-milestone-link grouped" + = link_to edit_project_milestone_path(milestone.project, milestone), class: "btn small edit-milestone-link grouped" do + %i.icon-edit + Edit %h4 - = link_to_gfm truncate(milestone.title, length: 100), project_milestone_path(milestone.project, milestone), class: "row_title" + = link_to_gfm truncate(milestone.title, length: 100), project_milestone_path(milestone.project, milestone) %small = milestone.expires_at - %br - .progress.progress-success.span3 + .row + .progress.progress-info.span4 .bar{style: "width: #{milestone.percent_complete}%;"} + .span6 + - if milestone.issues.any? + = link_to project_issues_path(milestone.project, milestone_id: milestone.id), class: "btn very_small" do + %strong= pluralize milestone.issues.count, 'Issue' - -   + - if milestone.merge_requests.any? + = link_to project_merge_requests_path(milestone.project, milestone_id: milestone.id), class: "btn very_small" do + %strong= pluralize milestone.issues.count, 'Merge Request' diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml index c113c81f..b8bc788c 100644 --- a/app/views/milestones/show.html.haml +++ b/app/views/milestones/show.html.haml @@ -31,10 +31,10 @@ %h5 Progress: %small - #{@milestone.issues.closed.count} closed + #{@milestone.closed_items_count} closed – - #{@milestone.issues.opened.count} open - .progress.progress-success + #{@milestone.open_items_count} open + .progress.progress-info .bar{style: "width: #{@milestone.percent_complete}%;"} @@ -58,15 +58,28 @@ %span.badge.badge-info ##{issue.id} – = link_to_gfm truncate(issue.title, length: 60), [@project, issue] - %br .span6 - %table + %table.milestone-merge-requests-filter %thead - %th Participants - - @users.each do |user| - %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 - = image_tag gravatar_icon(user.email, 24), width: "24" -   - = user.name + = link_to [@project, merge_request] do + %span.badge.badge-info ##{merge_request.id} + – + = link_to_gfm truncate(merge_request.title, length: 60), [@project, merge_request] + +%hr +%h6 Participants: +%div + - @users.each do |user| + = link_to tm_path(user.tm_of(@project)), class: 'float-link' do + = user.avatar_image + = user.name + +.clearfix diff --git a/db/migrate/20121026114600_add_milestone_id_to_merge_requests.rb b/db/migrate/20121026114600_add_milestone_id_to_merge_requests.rb new file mode 100644 index 00000000..b5167724 --- /dev/null +++ b/db/migrate/20121026114600_add_milestone_id_to_merge_requests.rb @@ -0,0 +1,5 @@ +class AddMilestoneIdToMergeRequests < ActiveRecord::Migration + def change + add_column :merge_requests, :milestone_id, :integer, :null => true + end +end diff --git a/db/schema.rb b/db/schema.rb index a7037811..51ab2072 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20121009205010) do +ActiveRecord::Schema.define(:version => 20121026114600) do create_table "events", :force => true do |t| t.string "target_type" @@ -73,6 +73,7 @@ ActiveRecord::Schema.define(:version => 20121009205010) do t.text "st_diffs", :limit => 2147483647 t.boolean "merged", :default => false, :null => false t.integer "state", :default => 1, :null => false + t.integer "milestone_id" end add_index "merge_requests", ["project_id"], :name => "index_merge_requests_on_project_id"