From 50a8f16e165d45bf6b518c0e250e1f5a360a6d3f Mon Sep 17 00:00:00 2001 From: Alex Braha Stoll Date: Tue, 13 Dec 2016 02:29:12 -0200 Subject: [PATCH] Add count badges to both dashboard and group milestones --- .../dashboard/milestones_controller.rb | 1 + .../groups/milestones_controller.rb | 1 + app/models/global_milestone.rb | 22 +++++++ .../dashboard/milestones/index.html.haml | 10 +-- app/views/groups/milestones/index.html.haml | 2 +- app/views/projects/milestones/index.html.haml | 10 +-- app/views/shared/_milestones_filter.html.haml | 12 +--- .../24421-personal-milestone-count-badges.yml | 4 ++ spec/models/global_milestone_spec.rb | 63 +++++++++++++++++++ 9 files changed, 105 insertions(+), 20 deletions(-) create mode 100644 changelogs/unreleased/24421-personal-milestone-count-badges.yml diff --git a/app/controllers/dashboard/milestones_controller.rb b/app/controllers/dashboard/milestones_controller.rb index 7f506db583f..df528d10f6e 100644 --- a/app/controllers/dashboard/milestones_controller.rb +++ b/app/controllers/dashboard/milestones_controller.rb @@ -5,6 +5,7 @@ class Dashboard::MilestonesController < Dashboard::ApplicationController def index respond_to do |format| format.html do + @milestone_states = GlobalMilestone.states_count(@projects) @milestones = Kaminari.paginate_array(milestones).page(params[:page]) end format.json do diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb index 0d872c86c8a..43102596201 100644 --- a/app/controllers/groups/milestones_controller.rb +++ b/app/controllers/groups/milestones_controller.rb @@ -6,6 +6,7 @@ class Groups::MilestonesController < Groups::ApplicationController def index respond_to do |format| format.html do + @milestone_states = GlobalMilestone.states_count(@projects) @milestones = Kaminari.paginate_array(milestones).page(params[:page]) end end diff --git a/app/models/global_milestone.rb b/app/models/global_milestone.rb index b991d78e27f..0afbca2cb32 100644 --- a/app/models/global_milestone.rb +++ b/app/models/global_milestone.rb @@ -28,6 +28,28 @@ class GlobalMilestone new(title, child_milestones) end + def self.states_count(projects) + relation = MilestonesFinder.new.execute(projects, state: 'all') + milestones_by_state_and_title = relation.reorder(nil).group(:state, :title).count + + opened = count_by_state(milestones_by_state_and_title, 'active') + closed = count_by_state(milestones_by_state_and_title, 'closed') + all = milestones_by_state_and_title.map { |(_, title), _| title }.uniq.count + + { + opened: opened, + closed: closed, + all: all + } + end + + def self.count_by_state(milestones_by_state_and_title, state) + milestones_by_state_and_title.count do |(milestone_state, _), _| + milestone_state == state + end + end + private_class_method :count_by_state + def initialize(title, milestones) @title = title @name = title diff --git a/app/views/dashboard/milestones/index.html.haml b/app/views/dashboard/milestones/index.html.haml index 917bfbd47e9..505b475f55b 100644 --- a/app/views/dashboard/milestones/index.html.haml +++ b/app/views/dashboard/milestones/index.html.haml @@ -1,11 +1,11 @@ -- page_title "Milestones" -- header_title "Milestones", dashboard_milestones_path +- page_title 'Milestones' +- header_title 'Milestones', dashboard_milestones_path .top-area - = render 'shared/milestones_filter' + = render 'shared/milestones_filter', counts: @milestone_states .nav-controls - = render 'shared/new_project_item_select', path: 'milestones/new', label: "New Milestone", include_groups: true + = render 'shared/new_project_item_select', path: 'milestones/new', label: 'New Milestone', include_groups: true .milestones %ul.content-list @@ -15,4 +15,4 @@ - else - @milestones.each do |milestone| = render 'milestone', milestone: milestone - = paginate @milestones, theme: "gitlab" + = paginate @milestones, theme: 'gitlab' diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml index 644895c56a1..6893168f039 100644 --- a/app/views/groups/milestones/index.html.haml +++ b/app/views/groups/milestones/index.html.haml @@ -2,7 +2,7 @@ = render "groups/head_issues" .top-area - = render 'shared/milestones_filter' + = render 'shared/milestones_filter', counts: @milestone_states .nav-controls - if can?(current_user, :admin_milestones, @group) diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml index ad2bfbec915..918f5d161bb 100644 --- a/app/views/projects/milestones/index.html.haml +++ b/app/views/projects/milestones/index.html.haml @@ -1,14 +1,14 @@ - @no_container = true -- page_title "Milestones" -= render "projects/issues/head" +- page_title 'Milestones' += render 'projects/issues/head' %div{ class: container_class } .top-area - = render 'shared/milestones_filter' + = render 'shared/milestones_filter', counts: milestone_counts(@project.milestones) .nav-controls - if can?(current_user, :admin_milestone, @project) - = link_to new_namespace_project_milestone_path(@project.namespace, @project), class: "btn btn-new", title: "New Milestone" do + = link_to new_namespace_project_milestone_path(@project.namespace, @project), class: 'btn btn-new', title: 'New Milestone' do New Milestone .milestones @@ -19,4 +19,4 @@ %li .nothing-here-block No milestones to show - = paginate @milestones, theme: "gitlab" + = paginate @milestones, theme: 'gitlab' diff --git a/app/views/shared/_milestones_filter.html.haml b/app/views/shared/_milestones_filter.html.haml index 704893b4d5b..57a0eaa919e 100644 --- a/app/views/shared/_milestones_filter.html.haml +++ b/app/views/shared/_milestones_filter.html.haml @@ -1,19 +1,13 @@ -- if @project - - counts = milestone_counts(@project.milestones) - %ul.nav-links %li{ class: milestone_class_for_state(params[:state], 'opened', true) }> = link_to milestones_filter_path(state: 'opened') do Open - - if @project - %span.badge= counts[:opened] + %span.badge= counts[:opened] %li{ class: milestone_class_for_state(params[:state], 'closed') }> = link_to milestones_filter_path(state: 'closed') do Closed - - if @project - %span.badge= counts[:closed] + %span.badge= counts[:closed] %li{ class: milestone_class_for_state(params[:state], 'all') }> = link_to milestones_filter_path(state: 'all') do All - - if @project - %span.badge= counts[:all] + %span.badge= counts[:all] diff --git a/changelogs/unreleased/24421-personal-milestone-count-badges.yml b/changelogs/unreleased/24421-personal-milestone-count-badges.yml new file mode 100644 index 00000000000..8bbc1ed2dde --- /dev/null +++ b/changelogs/unreleased/24421-personal-milestone-count-badges.yml @@ -0,0 +1,4 @@ +--- +title: Add dashboard and group milestones count badges +merge_request: 9836 +author: Alex Braha Stoll diff --git a/spec/models/global_milestone_spec.rb b/spec/models/global_milestone_spec.rb index cacbab8bcb1..55b87d1c48a 100644 --- a/spec/models/global_milestone_spec.rb +++ b/spec/models/global_milestone_spec.rb @@ -92,6 +92,41 @@ describe GlobalMilestone, models: true do end end + describe '.states_count' do + context 'when the projects have milestones' do + before do + create(:closed_milestone, title: 'Active Group Milestone', project: project3) + create(:active_milestone, title: 'Active Group Milestone', project: project1) + create(:active_milestone, title: 'Active Group Milestone', project: project2) + create(:closed_milestone, title: 'Closed Group Milestone', project: project1) + create(:closed_milestone, title: 'Closed Group Milestone', project: project2) + create(:closed_milestone, title: 'Closed Group Milestone', project: project3) + end + + it 'returns the quantity of global milestones in each possible state' do + expected_count = { opened: 1, closed: 2, all: 2 } + + count = GlobalMilestone.states_count(Project.all) + + expect(count).to eq(expected_count) + end + end + + context 'when the projects do not have milestones' do + before do + project1 + end + + it 'returns 0 as the quantity of global milestones in each state' do + expected_count = { opened: 0, closed: 0, all: 0 } + + count = GlobalMilestone.states_count(Project.all) + + expect(count).to eq(expected_count) + end + end + end + describe '#initialize' do let(:milestone1_project1) { create(:milestone, title: "Milestone v1.2", project: project1) } let(:milestone1_project2) { create(:milestone, title: "Milestone v1.2", project: project2) } @@ -127,4 +162,32 @@ describe GlobalMilestone, models: true do expect(global_milestone.safe_title).to eq('git-test') end end + + describe '#state' do + context 'when at least one milestone is active' do + it 'returns active' do + title = 'Active Group Milestone' + milestones = [ + create(:active_milestone, title: title), + create(:closed_milestone, title: title) + ] + global_milestone = GlobalMilestone.new(title, milestones) + + expect(global_milestone.state).to eq('active') + end + end + + context 'when all milestones are closed' do + it 'returns closed' do + title = 'Closed Group Milestone' + milestones = [ + create(:closed_milestone, title: title), + create(:closed_milestone, title: title) + ] + global_milestone = GlobalMilestone.new(title, milestones) + + expect(global_milestone.state).to eq('closed') + end + end + end end -- GitLab