diff options
-rw-r--r-- | app/controllers/groups/milestones_controller.rb | 6 | ||||
-rw-r--r-- | app/models/group_milestone.rb | 69 | ||||
-rw-r--r-- | app/services/milestones/group_service.rb | 10 | ||||
-rw-r--r-- | app/views/groups/milestones/_issue.html.haml | 9 | ||||
-rw-r--r-- | app/views/groups/milestones/_issues.html.haml | 6 | ||||
-rw-r--r-- | app/views/groups/milestones/_merge_request.html.haml | 6 | ||||
-rw-r--r-- | app/views/groups/milestones/_merge_requests.html.haml | 5 | ||||
-rw-r--r-- | app/views/groups/milestones/index.html.haml | 15 | ||||
-rw-r--r-- | app/views/groups/milestones/show.html.haml | 77 |
9 files changed, 190 insertions, 13 deletions
diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb index a86cc58c021..235b27f53a9 100644 --- a/app/controllers/groups/milestones_controller.rb +++ b/app/controllers/groups/milestones_controller.rb @@ -13,14 +13,16 @@ class Groups::MilestonesController < ApplicationController def show project_milestones = Milestone.where(project_id: group.projects) - @group_milestones = Milestones::GroupService.new(project_milestones).milestone(title) + @group_milestone = Milestones::GroupService.new(project_milestones).milestone(title) + @project_issues = @group_milestone.filter_by(params[:status], "issues") + @project_merge_requests = @group_milestone.filter_by(params[:status], "merge_requests") end def update project_milestones = Milestone.where(project_id: group.projects) @group_milestones = Milestones::GroupService.new(project_milestones).milestone(title) - @group_milestones.each do |milestone| + @group_milestones.milestones.each do |milestone| Milestones::UpdateService.new(milestone.project, current_user, params[:milestone]).execute(milestone) end diff --git a/app/models/group_milestone.rb b/app/models/group_milestone.rb index 567e0c2b9fb..0faff39ae7a 100644 --- a/app/models/group_milestone.rb +++ b/app/models/group_milestone.rb @@ -9,6 +9,10 @@ class GroupMilestone @title end + def safe_title + @title.gsub(".", "-") + end + def milestones @milestones end @@ -25,6 +29,10 @@ class GroupMilestone milestones.map{ |milestone| milestone.merge_requests.count }.sum end + def open_items_count + milestones.map{ |milestone| milestone.open_items_count }.sum + end + def closed_items_count milestones.map{ |milestone| milestone.closed_items_count }.sum end @@ -42,10 +50,69 @@ class GroupMilestone def state state = milestones.map{ |milestone| milestone.state } - if state.count("active") == state.size + if state.count('active') == state.size 'active' else 'closed' end end + + def active? + state == 'active' + end + + def closed? + state == 'closed' + end + + def opened_unassigned_issues + milestones.map{ |milestone| milestone.issues.opened.unassigned } + end + + def opened_assigned_issues + milestones.map{ |milestone| milestone.issues.opened.assigned } + end + + def closed_issues + milestones.map{ |milestone| milestone.issues.closed } + end + + def participants + milestones.map{ |milestone| milestone.participants.uniq }.reject(&:empty?).flatten + end + + def filter_by(filter, entity) + if entity + milestones = self.milestones.sort_by(&:project_id) + entities = {} + milestones.each do |project_milestone| + next unless project_milestone.send(entity).any? + project_name = project_milestone.project.name + entities_by_state = state_filter(filter, project_milestone.send(entity)) + entities.store(project_name, entities_by_state) + end + entities + else + {} + end + end + + def state_filter(filter, entities) + if entities.present? + sorted_entities = entities.sort_by(&:position) + entities_by_state = case filter + when 'active'; sorted_entities.group_by(&:state)['opened'] + when 'closed'; sorted_entities.group_by(&:state)['closed'] + else sorted_entities + end + if entities_by_state.blank? + [] + else + entities_by_state + end + else + [] + end + end + end diff --git a/app/services/milestones/group_service.rb b/app/services/milestones/group_service.rb index 39ae913a72a..2d1aa878c24 100644 --- a/app/services/milestones/group_service.rb +++ b/app/services/milestones/group_service.rb @@ -5,16 +5,22 @@ module Milestones end def execute - @project_milestones.map{ |title, milestone| GroupMilestone.new(title, milestone) } + build(@project_milestones) end def milestone(title) if title - @project_milestones[title] + group_milestone = @project_milestones[title].group_by(&:title) + build(group_milestone).first else nil end end + private + + def build(milestone) + milestone.map{ |title, milestones| GroupMilestone.new(title, milestones) } + end end end diff --git a/app/views/groups/milestones/_issue.html.haml b/app/views/groups/milestones/_issue.html.haml new file mode 100644 index 00000000000..7009400a46c --- /dev/null +++ b/app/views/groups/milestones/_issue.html.haml @@ -0,0 +1,9 @@ +%li{ id: dom_id(issue, 'sortable'), class: 'issue-row', 'data-iid' => issue.iid } + %span.str-truncated + - project = issue.project + = link_to [project, issue] do + %span.cgray ##{issue.iid} + = link_to_gfm issue.title, [project, issue] + .pull-right.assignee-icon + - if issue.assignee + = image_tag avatar_icon(issue.assignee.email, 16), class: "avatar s16" diff --git a/app/views/groups/milestones/_issues.html.haml b/app/views/groups/milestones/_issues.html.haml new file mode 100644 index 00000000000..3fefb2f0107 --- /dev/null +++ b/app/views/groups/milestones/_issues.html.haml @@ -0,0 +1,6 @@ +.panel.panel-default + .panel-heading= name + %ul{ class: "well-list issues-sortable-list" } + - issues.each do |issue| + = render 'issue', issue: issue + diff --git a/app/views/groups/milestones/_merge_request.html.haml b/app/views/groups/milestones/_merge_request.html.haml new file mode 100644 index 00000000000..4f11aaa74b7 --- /dev/null +++ b/app/views/groups/milestones/_merge_request.html.haml @@ -0,0 +1,6 @@ +%li{ id: dom_id(merge_request, 'sortable'), class: 'mr-row', 'data-iid' => merge_request.iid } + %span.str-truncated + - project = merge_request.project + = link_to [project, merge_request] do + %span.cgray ##{merge_request.iid} + = link_to_gfm truncate(merge_request.title, length: 60), [project, merge_request] diff --git a/app/views/groups/milestones/_merge_requests.html.haml b/app/views/groups/milestones/_merge_requests.html.haml new file mode 100644 index 00000000000..9bb213ffe32 --- /dev/null +++ b/app/views/groups/milestones/_merge_requests.html.haml @@ -0,0 +1,5 @@ +.panel.panel-default + .panel-heading= name + %ul{ class: "well-list merge_requests-sortable-list" } + - merge_requests.sort_by(&:position).each do |merge_request| + = render 'merge_request', merge_request: merge_request diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml index b93ff09d25c..e3dd1ae5ae0 100644 --- a/app/views/groups/milestones/index.html.haml +++ b/app/views/groups/milestones/index.html.haml @@ -22,21 +22,20 @@ .nothing-here-block No milestones to show - else - @group_milestones.each do |milestone| - %li{class: "milestone milestone-#{milestone.state == 'closed' ? 'closed' : 'open'}", id: dom_id(milestone.milestones.first) } + %li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone.milestones.first) } .pull-right - - safe_title = milestone.title.gsub(".", "-") - - if milestone.state == 'closed' - = link_to 'Reopen Milestone', group_milestone_path(@group, safe_title, milestone: {state_event: :activate }), method: :put, class: "btn btn-small btn-grouped" + - if milestone.closed? + = link_to 'Reopen Milestone', group_milestone_path(@group, milestone.safe_title, milestone: {state_event: :activate }), method: :put, class: "btn btn-small btn-grouped" - else - = link_to 'Close Milestone', group_milestone_path(@group, safe_title, milestone: {state_event: :close }), method: :put, class: "btn btn-small btn-remove" + = link_to 'Close Milestone', group_milestone_path(@group, milestone.safe_title, milestone: {state_event: :close }), method: :put, class: "btn btn-small btn-remove" %h4 - = link_to_gfm truncate(milestone.title, length: 100), group_milestone_path(@group, safe_title) + = link_to_gfm truncate(milestone.title, length: 100), group_milestone_path(@group, milestone.safe_title) %div %div - = link_to root_path do + = link_to group_milestone_path(@group, milestone.safe_title) do = pluralize milestone.issue_count, 'Issue' - = link_to root_path do + = link_to group_milestone_path(@group, milestone.safe_title) do = pluralize milestone.merge_requests_count, 'Merge Request' %span.light #{milestone.percent_complete}% complete diff --git a/app/views/groups/milestones/show.html.haml b/app/views/groups/milestones/show.html.haml new file mode 100644 index 00000000000..a450e7d09a5 --- /dev/null +++ b/app/views/groups/milestones/show.html.haml @@ -0,0 +1,77 @@ +%h3.page-title + Milestone #{@group_milestone.title} + .pull-right + - if @group_milestone.active? + = link_to 'Close Milestone', group_milestone_path(@group, @group_milestone.safe_title, milestone: {state_event: :close }), method: :put, class: "btn btn-small btn-remove" + - else + = link_to 'Reopen Milestone', group_milestone_path(@group, @group_milestone.safe_title, milestone: {state_event: :activate }), method: :put, class: "btn btn-small btn-grouped" + +- if (@group_milestone.total_items_count == @group_milestone.closed_items_count) && @group_milestone.active? + .alert.alert-success + %span All issues for this milestone are closed. You may close the milestone now. + +.back-link + = link_to group_milestones_path(@group) do + ← To milestones list + +.issue-box{ class: "issue-box-#{@group_milestone.closed? ? 'closed' : 'open'}" } + .state.clearfix + .state-label + - if @group_milestone.closed? + Closed + - else + Open + + %h4.title + = gfm escape_once(@group_milestone.title) + + .context + %p + Progress: + #{@group_milestone.closed_items_count} closed + – + #{@group_milestone.open_items_count} open + + .progress.progress-info + .progress-bar{style: "width: #{@group_milestone.percent_complete}%;"} + +%ul.nav.nav-tabs + %li.active + = link_to '#tab-issues', 'data-toggle' => 'tab' do + Issues + %span.badge= @group_milestone.issue_count + %li + = link_to '#tab-merge-requests', 'data-toggle' => 'tab' do + Merge Requests + %span.badge= @group_milestone.merge_requests_count + %li + = link_to '#tab-participants', 'data-toggle' => 'tab' do + Participants + %span.badge= @group_milestone.participants.count + +.tab-content + .tab-pane.active#tab-issues + .row + .col-md-4.responsive-side + = render 'groups/filter', entity: 'milestone' + .col-md-8 + - @project_issues.each do |name, issues| + = render 'issues', name: name, issues: issues + + .tab-pane#tab-merge-requests + .row + .col-md-4.responsive-side + = render 'groups/filter', entity: 'milestone' + .col-md-8 + - @project_merge_requests.each do |name, merge_requests| + = render 'merge_requests', name: name, merge_requests: merge_requests + + .tab-pane#tab-participants + %ul.bordered-list + - @group_milestone.participants.each do |user| + %li + = link_to user, title: user.name, class: "darken" do + = image_tag avatar_icon(user.email, 32), class: "avatar s32" + %strong= truncate(user.name, lenght: 40) + %br + %small.cgray= user.username |