diff --git a/app/controllers/concerns/milestone_actions.rb b/app/controllers/concerns/milestone_actions.rb index dbc575a14879a6c2f993ea01b5b2768213b7c7f7..29138e7b0143db932d7f257dd11a3e5374c18261 100644 --- a/app/controllers/concerns/milestone_actions.rb +++ b/app/controllers/concerns/milestone_actions.rb @@ -51,13 +51,7 @@ def tabs_json(partial, data = {}) } end - # rubocop:disable Gitlab/ModuleWithInstanceVariables def milestone_redirect_path - if @milestone.global_milestone? - url_for(action: :show, title: @milestone.title) - else - url_for(action: :show) - end + url_for(action: :show) end - # rubocop:enable Gitlab/ModuleWithInstanceVariables end diff --git a/app/controllers/dashboard/milestones_controller.rb b/app/controllers/dashboard/milestones_controller.rb index d34a07324dadb318145eafa52071924798df8015..14f9a026688ba4afd383db3a7b9b331194dae91e 100644 --- a/app/controllers/dashboard/milestones_controller.rb +++ b/app/controllers/dashboard/milestones_controller.rb @@ -1,48 +1,32 @@ # frozen_string_literal: true class Dashboard::MilestonesController < Dashboard::ApplicationController - include MilestoneActions - before_action :projects before_action :groups, only: :index - before_action :milestone, only: [:show, :merge_requests, :participants, :labels] def index respond_to do |format| format.html do - @milestone_states = Milestone.states_count(@projects.select(:id), @groups.select(:id)) - @milestones = Kaminari.paginate_array(milestones).page(params[:page]) + @milestone_states = Milestone.states_count(@projects.select(:id), groups.select(:id)) + @milestones = milestones.page(params[:page]) end format.json do - render json: milestones + render json: milestones.to_json(only: [:id, :title], methods: :name) end end end - def show - end - private - def group_milestones - DashboardGroupMilestone.build_collection(groups, params) - end - - # See [#39545](https://gitlab.com/gitlab-org/gitlab-foss/issues/39545) for info about the deprecation of dynamic milestones - def dynamic_milestones - DashboardMilestone.build_collection(@projects, params) - end - def milestones - @milestones = group_milestones + dynamic_milestones - end - - def milestone - @milestone = DashboardMilestone.build(@projects, params[:title]) - render_404 unless @milestone + MilestonesFinder.new(search_params).execute end def groups @groups ||= GroupsFinder.new(current_user, all_available: false).execute end + + def search_params + params.permit(:state, :search_title).merge(group_ids: groups, project_ids: projects) + end end diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb index 8cfbd29359773c61acc980c674b5dc399f5e07a9..8eddc07e926b94b987e35a01ad11bcdad584c111 100644 --- a/app/controllers/groups/milestones_controller.rb +++ b/app/controllers/groups/milestones_controller.rb @@ -13,10 +13,10 @@ def index respond_to do |format| format.html do @milestone_states = Milestone.states_count(group_projects_with_access, [group]) - @milestones = Kaminari.paginate_array(milestones).page(params[:page]) + @milestones = milestones.page(params[:page]) end format.json do - render json: milestones.map { |m| m.for_display.slice(:id, :title, :name) } + render json: milestones.to_json(only: [:id, :title], methods: :name) end end end @@ -29,7 +29,7 @@ def create @milestone = Milestones::CreateService.new(group, current_user, milestone_params).execute if @milestone.persisted? - redirect_to milestone_path + redirect_to milestone_path(@milestone) else render "new" end @@ -39,23 +39,15 @@ def show end def edit - render_404 if @milestone.legacy_group_milestone? end def update - # Keep this compatible with legacy group milestones where we have to update - # all projects milestones states at once. - milestones, update_params = get_milestones_for_update - milestones.each do |milestone| - Milestones::UpdateService.new(milestone.resource_parent, current_user, update_params).execute(milestone) - end + Milestones::UpdateService.new(@milestone.parent, current_user, milestone_params).execute(@milestone) - redirect_to milestone_path + redirect_to milestone_path(@milestone) end def destroy - return render_404 if @milestone.legacy_group_milestone? - Milestones::DestroyService.new(group, current_user).execute(@milestone) respond_to do |format| @@ -66,14 +58,6 @@ def destroy private - def get_milestones_for_update - if @milestone.legacy_group_milestone? - [@milestone.milestones, legacy_milestone_params] - else - [[@milestone], milestone_params] - end - end - def authorize_admin_milestones! return render_404 unless can?(current_user, :admin_milestone, group) end @@ -82,27 +66,21 @@ def milestone_params params.require(:milestone).permit(:title, :description, :start_date, :due_date, :state_event) end - def legacy_milestone_params - params.require(:milestone).permit(:state_event) + def milestones + MilestonesFinder.new(search_params).execute end - def milestone_path - if @milestone.legacy_group_milestone? - group_milestone_path(group, @milestone.safe_title, title: @milestone.title) - else - group_milestone_path(group, @milestone.iid) - end + def milestone + @milestone = group.milestones.find_by_iid(params[:id]) + + render_404 unless @milestone end - def milestones - milestones = MilestonesFinder.new(search_params).execute + def search_params + groups = request.format.json? ? group_ids(include_ancestors: true) : group_ids @sort = params[:sort] || 'due_date_asc' - MilestoneArray.sort(milestones + legacy_milestones, @sort) - end - - def legacy_milestones - GroupMilestone.build_collection(group, group_projects_with_access, params) + params.permit(:state, :search_title).merge(sort: @sort, group_ids: groups, project_ids: group_projects_with_access) end def group_projects_with_access @@ -116,23 +94,6 @@ def group_ids(include_ancestors: false) group.self_and_descendants.public_or_visible_to_user(current_user).select(:id) end end - - def milestone - @milestone = - if params[:title] - GroupMilestone.build(group, group_projects_with_access, params[:title]) - else - group.milestones.find_by_iid(params[:id]) - end - - render_404 unless @milestone - end - - def search_params - groups = request.format.json? ? group_ids(include_ancestors: true) : group_ids - - params.permit(:state, :search_title).merge(group_ids: groups) - end end Groups::MilestonesController.prepend_if_ee('EE::Groups::MilestonesController') diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb index 56f1f1a1019c36f44dc8a690f7b9a1a920c9b3cc..886ae262a487285e57303e7863ccbc324656b4c5 100644 --- a/app/controllers/projects/milestones_controller.rb +++ b/app/controllers/projects/milestones_controller.rb @@ -34,7 +34,7 @@ def index @milestones = @milestones.page(params[:page]) end format.json do - render json: @milestones.to_json(methods: :name) + render json: @milestones.to_json(only: [:id, :title], methods: :name) end end end diff --git a/app/finders/milestones_finder.rb b/app/finders/milestones_finder.rb index cfe648d9f7917f6f854a082ec8bf67c1094562ef..8f0cdf3b255c8998e48bb488abf84f9efbd01336 100644 --- a/app/finders/milestones_finder.rb +++ b/app/finders/milestones_finder.rb @@ -58,10 +58,8 @@ def by_state(items) Milestone.filter_by_state(items, params[:state]) end - # rubocop: disable CodeReuse/ActiveRecord def order(items) - order_statement = Gitlab::Database.nulls_last_order('due_date', 'ASC') - items.reorder(order_statement).order('title ASC') + sort_by = params[:sort].presence || 'due_date_asc' + items.sort_by_attribute(sort_by) end - # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/helpers/timeboxes_helper.rb b/app/helpers/timeboxes_helper.rb index 87ea22d8f83e3171dabb02c55eede2f55131be5c..0bffdba7349c15859cc6fadb997c149aac7e87da 100644 --- a/app/helpers/timeboxes_helper.rb +++ b/app/helpers/timeboxes_helper.rb @@ -229,11 +229,7 @@ def timebox_date_range(timebox) alias_method :milestone_date_range, :timebox_date_range def milestone_tab_path(milestone, tab) - if milestone.global_milestone? - url_for(action: tab, title: milestone.title, format: :json) - else - url_for(action: tab, format: :json) - end + url_for(action: tab, format: :json) end def update_milestone_path(milestone, params = {}) @@ -247,11 +243,7 @@ def update_milestone_path(milestone, params = {}) def group_milestone_route(milestone, params = {}) params = nil if params.empty? - if milestone.legacy_group_milestone? - group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: params) - else - group_milestone_path(milestone.group, milestone.iid, milestone: params) - end + group_milestone_path(milestone.group, milestone.iid, milestone: params) end def group_or_project_milestone_path(milestone) diff --git a/app/models/concerns/milestoneish.rb b/app/models/concerns/milestoneish.rb index fa5a79cc12bfb1348f06fc6cdd4fbd7851dd451a..5f24564dc56088843739ffb960dc68ce5cc74000 100644 --- a/app/models/concerns/milestoneish.rb +++ b/app/models/concerns/milestoneish.rb @@ -97,26 +97,6 @@ def expired? due_date && due_date.past? end - def group_milestone? - false - end - - def project_milestone? - false - end - - def legacy_group_milestone? - false - end - - def dashboard_milestone? - false - end - - def global_milestone? - false - end - def total_time_spent @total_time_spent ||= issues.joins(:timelogs).sum(:time_spent) + merge_requests.joins(:timelogs).sum(:time_spent) end diff --git a/app/models/dashboard_group_milestone.rb b/app/models/dashboard_group_milestone.rb deleted file mode 100644 index 48c09f4cd6bee32b50628c56f1ffdb663e05d553..0000000000000000000000000000000000000000 --- a/app/models/dashboard_group_milestone.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true -# Dashboard Group Milestones are milestones that allow us to pull more info out for the UI that the Milestone object doesn't allow for -class DashboardGroupMilestone < GlobalMilestone - extend ::Gitlab::Utils::Override - - attr_reader :group_name - - def initialize(milestone) - super - - @group_name = milestone.group.full_name - end - - def self.build_collection(groups, params) - milestones = Milestone.of_groups(groups.select(:id)) - .reorder_by_due_date_asc - .order_by_name_asc - milestones = milestones.search_title(params[:search_title]) if params[:search_title].present? - Milestone.filter_by_state(milestones, params[:state]).map { |m| new(m) } - end - - def dashboard_milestone? - true - end - - def merge_requests_enabled? - true - end -end diff --git a/app/models/dashboard_milestone.rb b/app/models/dashboard_milestone.rb deleted file mode 100644 index fd59b94b737a49c20c903dcc26d89721e6aa4d10..0000000000000000000000000000000000000000 --- a/app/models/dashboard_milestone.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -class DashboardMilestone < GlobalMilestone - attr_reader :project_name - - def initialize(milestone) - super - - @project_name = milestone.project.full_name - end - - def project_milestone? - true - end - - def merge_requests_enabled? - project.merge_requests_enabled? - end -end diff --git a/app/models/global_milestone.rb b/app/models/global_milestone.rb deleted file mode 100644 index 43de7454cb753f289947b236ba8ced01ffdfb77f..0000000000000000000000000000000000000000 --- a/app/models/global_milestone.rb +++ /dev/null @@ -1,108 +0,0 @@ -# frozen_string_literal: true -# Global Milestones are milestones that can be shared across multiple projects -class GlobalMilestone - include Milestoneish - - STATE_COUNT_HASH = { opened: 0, closed: 0, all: 0 }.freeze - - attr_reader :milestone - alias_attribute :name, :title - - delegate :title, :state, :due_date, :start_date, :participants, :project, - :group, :expires_at, :closed?, :iid, :group_milestone?, :safe_title, - :timebox_id, :milestoneish_id, :resource_parent, :releases, to: :milestone - - def to_hash - { - name: title, - title: title, - group_name: group&.full_name, - project_name: project&.full_name - } - end - - def for_display - @milestone - end - - def self.build_collection(projects, params) - items = Milestone.of_projects(projects) - .reorder_by_due_date_asc - .order_by_name_asc - items = items.search_title(params[:search_title]) if params[:search_title].present? - - Milestone.filter_by_state(items, params[:state]).map { |m| new(m) } - end - - # necessary for legacy milestones - def self.build(projects, title) - milestones = Milestone.of_projects(projects).where(title: title) - return if milestones.blank? - - new(milestones.first) - end - - def self.states_count(projects, group = nil) - legacy_group_milestones_count = legacy_group_milestone_states_count(projects) - group_milestones_count = group_milestones_states_count(group) - - legacy_group_milestones_count.merge(group_milestones_count) do |k, legacy_group_milestones_count, group_milestones_count| - legacy_group_milestones_count + group_milestones_count - end - end - - def self.group_milestones_states_count(group) - return STATE_COUNT_HASH unless group - - counts_by_state = Milestone.of_groups(group).count_by_state - - { - opened: counts_by_state['active'] || 0, - closed: counts_by_state['closed'] || 0, - all: counts_by_state.values.sum - } - end - - def self.legacy_group_milestone_states_count(projects) - return STATE_COUNT_HASH unless projects - - # We need to reorder(nil) on the projects, because the controller passes them in sorted. - relation = Milestone.of_projects(projects.reorder(nil)).count_by_state - - { - opened: relation['active'] || 0, - closed: relation['closed'] || 0, - all: relation.values.sum - } - end - - def initialize(milestone) - @milestone = milestone - end - - def active? - state == 'active' - end - - def closed? - state == 'closed' - end - - def issues - @issues ||= Issue.of_milestones(milestone).includes(:project, :assignees, :labels) - end - - def merge_requests - @merge_requests ||= MergeRequest.of_milestones(milestone).includes(:target_project, :assignees, :labels) - end - - def labels - @labels ||= GlobalLabel.build_collection(milestone.labels).sort_by!(&:title) - end - - def global_milestone? - true - end -end - -GlobalMilestone.include_if_ee('::EE::GlobalMilestone') diff --git a/app/models/group_milestone.rb b/app/models/group_milestone.rb deleted file mode 100644 index 60e97174e5080e5964545fea575f22f44afacdb3..0000000000000000000000000000000000000000 --- a/app/models/group_milestone.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true -# Group Milestones are milestones that can be shared among many projects within the same group -class GroupMilestone < GlobalMilestone - attr_reader :group, :milestones - - def self.build_collection(group, projects, params) - params = - { state: params[:state], search_title: params[:search_title] } - - project_milestones = Milestone.of_projects(projects) - project_milestones = project_milestones.search_title(params[:search_title]) if params[:search_title].present? - child_milestones = Milestone.filter_by_state(project_milestones, params[:state]) - grouped_milestones = child_milestones.group_by(&:title) - - grouped_milestones.map do |title, grouped| - new(title, grouped, group) - end - end - - def self.build(group, projects, title) - child_milestones = Milestone.of_projects(projects).where(title: title) - return if child_milestones.blank? - - new(title, child_milestones, group) - end - - def initialize(title, milestones, group) - @milestones = milestones - @group = group - end - - def milestone - @milestone ||= milestones.find { |m| m.description.present? } || milestones.first - end - - def issues_finder_params - { group_id: group.id } - end - - def legacy_group_milestone? - true - end - - def merge_requests_enabled? - true - end -end - -GroupMilestone.include_if_ee('::EE::GroupMilestone') diff --git a/app/views/dashboard/milestones/_milestone.html.haml b/app/views/dashboard/milestones/_milestone.html.haml index 89212eb6bf9aa6369436e0e253b5403a2fd0a4b4..4921de32f65391291582a2baecaeac9cb9701e86 100644 --- a/app/views/dashboard/milestones/_milestone.html.haml +++ b/app/views/dashboard/milestones/_milestone.html.haml @@ -1,5 +1,4 @@ = render 'shared/milestones/milestone', - milestone_path: group_or_project_milestone_path(milestone), issues_path: issues_dashboard_path(milestone_title: milestone.title), merge_requests_path: merge_requests_dashboard_path(milestone_title: milestone.title), milestone: milestone, diff --git a/app/views/dashboard/milestones/show.html.haml b/app/views/dashboard/milestones/show.html.haml deleted file mode 100644 index 2129920afd274b5512b085b693858eb277ce8b1a..0000000000000000000000000000000000000000 --- a/app/views/dashboard/milestones/show.html.haml +++ /dev/null @@ -1,5 +0,0 @@ -- header_title "Milestones", dashboard_milestones_path - -= render 'shared/milestones/top', milestone: @milestone -= render 'shared/milestones/tabs', milestone: @milestone, show_full_project_name: true -= render 'shared/milestones/sidebar', milestone: @milestone, affix_offset: 51 diff --git a/app/views/groups/milestones/_milestone.html.haml b/app/views/groups/milestones/_milestone.html.haml index bae8997e24c093d5aba8fc08851a2dc336bb0ee0..b73626dab8143b4269a7e8981a9ee188532d81f1 100644 --- a/app/views/groups/milestones/_milestone.html.haml +++ b/app/views/groups/milestones/_milestone.html.haml @@ -1,6 +1,4 @@ - = render 'shared/milestones/milestone', - milestone_path: group_milestone_route(milestone), issues_path: issues_group_path(@group, milestone_title: milestone.title), merge_requests_path: merge_requests_group_path(@group, milestone_title: milestone.title), milestone: milestone diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml index b6fb908c8f644a5b16008cd162543e7726b3c8bc..03407adb57d58d74ebef39ab9535268c208d03a0 100644 --- a/app/views/groups/milestones/index.html.haml +++ b/app/views/groups/milestones/index.html.haml @@ -16,5 +16,8 @@ .nothing-here-block No milestones to show - else - @milestones.each do |milestone| - = render 'milestone', milestone: milestone + - if milestone.project_milestone? + = render 'projects/milestones/milestone', milestone: milestone + - else + = render 'milestone', milestone: milestone = paginate @milestones, theme: "gitlab" diff --git a/app/views/projects/milestones/_milestone.html.haml b/app/views/projects/milestones/_milestone.html.haml index bc82b45f9023dfe0f7129e1f278dbf19d607031f..00937c5bf732e56893025851bdaab4a22622e500 100644 --- a/app/views/projects/milestones/_milestone.html.haml +++ b/app/views/projects/milestones/_milestone.html.haml @@ -1,5 +1,4 @@ = render 'shared/milestones/milestone', - milestone_path: project_milestone_path(milestone.project, milestone), issues_path: project_issues_path(milestone.project, milestone_title: milestone.title), merge_requests_path: project_merge_requests_path(milestone.project, milestone_title: milestone.title), milestone: milestone diff --git a/app/views/shared/milestones/_header.html.haml b/app/views/shared/milestones/_header.html.haml index 2da857261d166bee9b35386ad0e4a3ec3f0e591d..99a46f1fb8522cee74ca769f4d4b0adf10850f7e 100644 --- a/app/views/shared/milestones/_header.html.haml +++ b/app/views/shared/milestones/_header.html.haml @@ -11,8 +11,7 @@ .milestone-buttons - if can?(current_user, :admin_milestone, @group || @project) - - unless milestone.legacy_group_milestone? - = link_to _('Edit'), edit_milestone_path(milestone), class: 'btn btn-grouped' + = link_to _('Edit'), edit_milestone_path(milestone), class: 'btn btn-grouped' - if milestone.project_milestone? && milestone.project.group %button.js-promote-project-milestone-button.btn.btn-grouped{ data: { toggle: 'modal', @@ -31,8 +30,7 @@ - else = link_to _('Reopen milestone'), update_milestone_path(milestone, { state_event: :activate }), method: :put, class: 'btn btn-grouped btn-reopen' - - unless milestone.legacy_group_milestone? - = render 'shared/milestones/delete_button' + = render 'shared/milestones/delete_button' %button.btn.btn-default.btn-grouped.float-right.d-block.d-sm-none.js-sidebar-toggle{ type: 'button' } = icon('angle-double-left') diff --git a/app/views/shared/milestones/_milestone.html.haml b/app/views/shared/milestones/_milestone.html.haml index 9f61082d605d1b30c9527f4182aa5be4382e59be..a951c0a5119f2d1ad40cd55ebe3a6ace1aa5ea5e 100644 --- a/app/views/shared/milestones/_milestone.html.haml +++ b/app/views/shared/milestones/_milestone.html.haml @@ -6,39 +6,33 @@ .row .col-sm-6 .append-bottom-5 - %strong= link_to truncate(milestone.title, length: 100), milestone_path + %strong= link_to truncate(milestone.title, length: 100), milestone_path(milestone) - if @group = " - #{milestone_type}" - - if @project || milestone.is_a?(GlobalMilestone) || milestone.group_milestone? - - if milestone.due_date || milestone.start_date - .text-tertiary.append-bottom-5 - = milestone_date_range(milestone) - - recent_releases, total_count, more_count = recent_releases_with_counts(milestone) - - unless total_count.zero? - .text-tertiary.append-bottom-5.milestone-release-links - = icon('rocket') - = n_('Release', 'Releases', total_count) - - recent_releases.each do |release| - = link_to release.name, project_releases_path(release.project, anchor: release.tag) - - unless release == recent_releases.last - • - - if total_count > recent_releases.count + - if milestone.due_date || milestone.start_date + .text-tertiary.append-bottom-5 + = milestone_date_range(milestone) + - recent_releases, total_count, more_count = recent_releases_with_counts(milestone) + - unless total_count.zero? + .text-tertiary.append-bottom-5.milestone-release-links + = icon('rocket') + = n_('Release', 'Releases', total_count) + - recent_releases.each do |release| + = link_to release.name, project_releases_path(release.project, anchor: release.tag) + - unless release == recent_releases.last • - = link_to n_('%{count} more release', '%{count} more releases', more_count) % { count: more_count }, project_releases_path(milestone.project) - %div - = render('shared/milestone_expired', milestone: milestone) - - if milestone.group_milestone? - .label-badge.label-badge-blue.d-inline-block - = milestone.group.full_name - - if milestone.legacy_group_milestone? - .projects - - link_to milestone_path(milestone.milestone) do - %span.label-badge.label-badge-blue.d-inline-block.append-bottom-5 - = dashboard ? milestone.project.full_name : milestone.project.name - - if milestone.project - .label-badge.label-badge-gray.d-inline-block - = milestone.project.full_name + - if total_count > recent_releases.count + • + = link_to n_('%{count} more release', '%{count} more releases', more_count) % { count: more_count }, project_releases_path(milestone.project) + %div + = render('shared/milestone_expired', milestone: milestone) + - if milestone.group_milestone? + .label-badge.label-badge-blue.d-inline-block + = milestone.group.full_name + - if milestone.project_milestone? + .label-badge.label-badge-gray.d-inline-block + = milestone.project.full_name .col-sm-4.milestone-progress = milestone_progress_bar(milestone) @@ -49,29 +43,25 @@ .float-lg-right.light #{milestone.percent_complete}% complete .col-sm-2 .milestone-actions.d-flex.justify-content-sm-start.justify-content-md-end - - if @project - - if can_admin_project_milestones? and milestone.active? - - if can_admin_group_milestones? - %button.js-promote-project-milestone-button.btn.btn-blank.btn-sm.btn-grouped.has-tooltip{ title: s_('Milestones|Promote to Group Milestone'), - disabled: true, - type: 'button', - data: { url: promote_project_milestone_path(milestone.project, milestone), - milestone_title: milestone.title, - group_name: @project.group.name, - target: '#promote-milestone-modal', - container: 'body', - toggle: 'modal' } } - = sprite_icon('level-up', size: 14) + - if @project # if in milestones list on project level + - if can_admin_group_milestones? + %button.js-promote-project-milestone-button.btn.btn-blank.btn-sm.btn-grouped.has-tooltip{ title: s_('Milestones|Promote to Group Milestone'), + disabled: true, + type: 'button', + data: { url: promote_project_milestone_path(milestone.project, milestone), + milestone_title: milestone.title, + group_name: @project.group.name, + target: '#promote-milestone-modal', + container: 'body', + toggle: 'modal' } } + = sprite_icon('level-up', size: 14) + + - if can?(current_user, :admin_milestone, milestone) + - if milestone.closed? + = link_to s_('Milestones|Reopen Milestone'), milestone_path(milestone, milestone: { state_event: :activate }), method: :put, class: "btn btn-sm btn-grouped btn-reopen" + - else + = link_to s_('Milestones|Close Milestone'), milestone_path(milestone, milestone: { state_event: :close }), method: :put, class: "btn btn-sm btn-grouped btn-close" - = link_to s_('Milestones|Close Milestone'), project_milestone_path(@project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-sm btn-close btn-grouped" - - unless milestone.active? - = link_to s_('Milestones|Reopen Milestone'), project_milestone_path(@project, milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen" - - if @group - - if can?(current_user, :admin_milestone, @group) - - if milestone.closed? - = link_to s_('Milestones|Reopen Milestone'), group_milestone_route(milestone, {state_event: :activate }), method: :put, class: "btn btn-sm btn-grouped btn-reopen" - - else - = link_to s_('Milestones|Close Milestone'), group_milestone_route(milestone, {state_event: :close }), method: :put, class: "btn btn-sm btn-grouped btn-close" - if dashboard .label-badge.label-badge-gray = milestone_type diff --git a/app/views/shared/milestones/_top.html.haml b/app/views/shared/milestones/_top.html.haml index 5f53e6316afce9c3d91b52ed6760952e009e5b82..49df00940b7b8a0ba764d3f88bf8d04583e862b0 100644 --- a/app/views/shared/milestones/_top.html.haml +++ b/app/views/shared/milestones/_top.html.haml @@ -1,11 +1,9 @@ - page_title milestone.title -- @breadcrumb_link = dashboard_milestone_path(milestone.safe_title, title: milestone.title) +- @breadcrumb_link = milestone_path(milestone) - group = local_assigns[:group] -- is_dynamic_milestone = milestone.legacy_group_milestone? || milestone.dashboard_milestone? = render 'shared/milestones/header', milestone: milestone -= render 'shared/milestones/deprecation_message' if is_dynamic_milestone = render 'shared/milestones/description', milestone: milestone - if milestone.complete? && milestone.active? @@ -15,26 +13,3 @@ = group ? _('You may close the milestone now.') : _('Navigate to the project to close the milestone.') = render_if_exists 'shared/milestones/burndown', milestone: milestone, project: @project - -- if is_dynamic_milestone - .table-holder - %table.table - %thead - %tr - %th= _('Project') - %th= _('Open issues') - %th= _('State') - %th= _('Due date') - %tr - %td - - project_name = group ? milestone.project.name : milestone.project.full_name - = link_to project_name, milestone_path(milestone.milestone) - %td - = milestone.milestone.issues_visible_to_user(current_user).opened.count - %td - - if milestone.closed? - = _('Closed') - - else - = _('Open') - %td - = milestone.expires_at diff --git a/changelogs/unreleased/39545-cleanup-dynamic-milestone-pages.yml b/changelogs/unreleased/39545-cleanup-dynamic-milestone-pages.yml new file mode 100644 index 0000000000000000000000000000000000000000..e2ab210a3330c13b43855b5324fee749ceca49ac --- /dev/null +++ b/changelogs/unreleased/39545-cleanup-dynamic-milestone-pages.yml @@ -0,0 +1,5 @@ +--- +title: Remove deprecated dashboard & group milestone pages +merge_request: 13237 +author: +type: removed diff --git a/config/routes/dashboard.rb b/config/routes/dashboard.rb index f1e8c2b9d8251f9f242d649520d85ab75e46b469..7e29a36f02022e1e978011b04de13d0da637f697 100644 --- a/config/routes/dashboard.rb +++ b/config/routes/dashboard.rb @@ -5,13 +5,7 @@ get :activity scope module: :dashboard do - resources :milestones, only: [:index, :show] do - member do - get :merge_requests - get :participants - get :labels - end - end + resources :milestones, only: [:index] resources :labels, only: [:index] resources :groups, only: [:index] diff --git a/ee/app/controllers/ee/groups/milestones_controller.rb b/ee/app/controllers/ee/groups/milestones_controller.rb index 317491181be16e9e76891b1dde8175a58a9d7881..8496cc132d7138a1aabb4539a924fbd50c7f2605 100644 --- a/ee/app/controllers/ee/groups/milestones_controller.rb +++ b/ee/app/controllers/ee/groups/milestones_controller.rb @@ -5,9 +5,9 @@ module Groups module MilestonesController extend ::Gitlab::Utils::Override - override :legacy_milestones - def legacy_milestones - params[:only_group_milestones] ? [] : super + override :search_params + def search_params + params[:only_group_milestones].present? ? super.merge(project_ids: []) : super end end end diff --git a/ee/app/models/ee/global_milestone.rb b/ee/app/models/ee/global_milestone.rb deleted file mode 100644 index a98b75bf6b4f58c9b1596ce6f28597c923626eb2..0000000000000000000000000000000000000000 --- a/ee/app/models/ee/global_milestone.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -module EE - module GlobalMilestone - def supports_weight? - false - end - - # Legacy group milestones or dashboard milestones (grouped by title) - # can't present Burndown charts since they don't have - # proper limits set. - def supports_burndown_charts? - false - end - end -end diff --git a/ee/app/models/ee/group_milestone.rb b/ee/app/models/ee/group_milestone.rb deleted file mode 100644 index c74f4129b7e9bf7cd334f376755c7da11920ea91..0000000000000000000000000000000000000000 --- a/ee/app/models/ee/group_milestone.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -module EE - module GroupMilestone - def supports_weight? - group&.feature_available?(:issue_weights) - end - end -end diff --git a/ee/spec/features/burndown_charts_spec.rb b/ee/spec/features/burndown_charts_spec.rb index 62e5f636aad1d515466db352ace89358e385c408..82c3c9649d80829f068e14d19e01b975c1fb9198 100644 --- a/ee/spec/features/burndown_charts_spec.rb +++ b/ee/spec/features/burndown_charts_spec.rb @@ -70,23 +70,4 @@ expect(page).to have_content('Improve milestones with Burndown Charts') end end - - describe 'grouped by title milestones' do - let(:group) { nil } - let(:project) { create(:project) } - - before do - project.add_maintainer(current_user) - end - - it 'does not present burndown chart or promotion' do - allow(License).to receive(:current) { nil } - allow(Gitlab::CurrentSettings).to receive(:should_check_namespace_plan?) { true } - - visit dashboard_milestone_path(milestone.safe_title, title: milestone.title) - - expect(page).not_to have_css('.burndown-chart') - expect(page).not_to have_content('Improve milestones with Burndown Charts') - end - end end diff --git a/lib/milestone_array.rb b/lib/milestone_array.rb deleted file mode 100644 index 461e73e96703b6af602007503c606f051b368fb7..0000000000000000000000000000000000000000 --- a/lib/milestone_array.rb +++ /dev/null @@ -1,42 +0,0 @@ -# frozen_string_literal: true - -module MilestoneArray - class << self - def sort(array, sort_method) - case sort_method - when 'due_date_asc' - sort_asc_nulls_last(array, 'due_date') - when 'due_date_desc' - sort_desc_nulls_last(array, 'due_date') - when 'start_date_asc' - sort_asc_nulls_last(array, 'start_date') - when 'start_date_desc' - sort_desc_nulls_last(array, 'start_date') - when 'name_asc' - sort_asc(array, 'title') - when 'name_desc' - sort_asc(array, 'title').reverse - else - array - end - end - - private - - def sort_asc_nulls_last(array, attribute) - attribute = attribute.to_sym - - array.select(&attribute).sort_by(&attribute) + array.reject(&attribute) - end - - def sort_desc_nulls_last(array, attribute) - attribute = attribute.to_sym - - array.select(&attribute).sort_by(&attribute).reverse + array.reject(&attribute) - end - - def sort_asc(array, attribute) - array.sort_by(&attribute.to_sym) - end - end -end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index e8191e1cb4fc9f6e2682624c7abb7674d7fa4780..f06836e6e8c7d022aeea655ef5acdb4427de2176 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -20730,9 +20730,6 @@ msgstr "" msgid "Starts at (UTC)" msgstr "" -msgid "State" -msgstr "" - msgid "State your message to activate" msgstr "" diff --git a/spec/controllers/dashboard/milestones_controller_spec.rb b/spec/controllers/dashboard/milestones_controller_spec.rb index f4b04ad6dee3bf2fe4967883c64b5d4075c625d3..36c1e2d716900034e78504601d80db62c89fea64 100644 --- a/spec/controllers/dashboard/milestones_controller_spec.rb +++ b/spec/controllers/dashboard/milestones_controller_spec.rb @@ -8,12 +8,7 @@ let(:user) { create(:user) } let(:project_milestone) { create(:milestone, project: project) } let(:group_milestone) { create(:milestone, group: group) } - let(:milestone) do - DashboardMilestone.build( - [project], - project_milestone.title - ) - end + let(:milestone) { create(:milestone, group: group) } let(:issue) { create(:issue, project: project, milestone: project_milestone) } let(:group_issue) { create(:issue, milestone: group_milestone, project: create(:project, group: group)) } @@ -28,22 +23,6 @@ group.add_developer(user) end - it_behaves_like 'milestone tabs' - - describe "#show" do - render_views - - def view_milestone - get :show, params: { id: milestone.safe_title, title: milestone.title } - end - - it 'shows milestone page' do - view_milestone - - expect(response).to have_gitlab_http_status(:ok) - end - end - describe "#index" do let(:public_group) { create(:group, :public) } let!(:public_milestone) { create(:milestone, group: public_group) } @@ -58,7 +37,6 @@ def view_milestone expect(response).to have_gitlab_http_status(:ok) expect(json_response.size).to eq(2) expect(json_response.map { |i| i["name"] }).to match_array([group_milestone.name, project_milestone.name]) - expect(json_response.map { |i| i["group_name"] }.compact).to match_array(group.name) end it 'returns closed group and project milestones to which the user belongs' do @@ -67,7 +45,6 @@ def view_milestone expect(response).to have_gitlab_http_status(:ok) expect(json_response.size).to eq(2) expect(json_response.map { |i| i["name"] }).to match_array([closed_group_milestone.name, closed_project_milestone.name]) - expect(json_response.map { |i| i["group_name"] }.compact).to match_array(group.name) end it 'searches legacy project milestones by title when search_title is given' do diff --git a/spec/controllers/groups/milestones_controller_spec.rb b/spec/controllers/groups/milestones_controller_spec.rb index afb950bc5389934413be64444acc57c165980d5a..fa297fa2b5ec65bfc152ff337b0c723760e8ad1b 100644 --- a/spec/controllers/groups/milestones_controller_spec.rb +++ b/spec/controllers/groups/milestones_controller_spec.rb @@ -8,15 +8,7 @@ let!(:project2) { create(:project, group: group) } let(:user) { create(:user) } let(:title) { 'è‚¯å®šä¸æ˜¯ä¸æ–‡çš„问题' } - let(:milestone) do - project_milestone = create(:milestone, project: project) - - GroupMilestone.build( - group, - [project], - project_milestone.title - ) - end + let(:milestone) { create(:milestone, project: project) } let(:milestone_path) { group_milestone_path(group, milestone.safe_title, title: milestone.title) } let(:milestone_params) do @@ -168,17 +160,16 @@ context 'as JSON' do let!(:milestone) { create(:milestone, group: group, title: 'group milestone') } - let!(:legacy_milestone1) { create(:milestone, project: project, title: 'legacy') } - let!(:legacy_milestone2) { create(:milestone, project: project2, title: 'legacy') } + let!(:project_milestone1) { create(:milestone, project: project, title: 'same name') } + let!(:project_milestone2) { create(:milestone, project: project2, title: 'same name') } - it 'lists legacy group milestones and group milestones' do + it 'lists project and group milestones' do get :index, params: { group_id: group.to_param }, format: :json milestones = json_response - expect(milestones.count).to eq(2) - expect(milestones.first["title"]).to eq("group milestone") - expect(milestones.second["title"]).to eq("legacy") + expect(milestones.count).to eq(3) + expect(milestones.collect { |m| m['title'] }).to match_array(['same name', 'same name', 'group milestone']) expect(response).to have_gitlab_http_status(:ok) expect(response.content_type).to eq 'application/json' end @@ -191,8 +182,9 @@ get :index, params: { group_id: group.to_param }, format: :json milestones = json_response - expect(milestones.count).to eq(3) - expect(milestones.second["title"]).to eq("subgroup milestone") + milestone_titles = milestones.map { |m| m['title'] } + expect(milestones.count).to eq(4) + expect(milestone_titles).to match_array(['same name', 'same name', 'group milestone', 'subgroup milestone']) end end @@ -218,31 +210,18 @@ end describe '#show' do - let(:milestone1) { create(:milestone, project: project, title: 'legacy') } - let(:milestone2) { create(:milestone, project: project, title: 'legacy') } - let(:group_milestone) { create(:milestone, group: group) } + render_views - context 'when there is a title parameter' do - it 'searches for a legacy group milestone' do - expect(GroupMilestone).to receive(:build) - expect(Milestone).not_to receive(:find_by_iid) + let!(:group_milestone) { create(:milestone, group: group) } - get :show, params: { group_id: group.to_param, id: title, title: milestone1.safe_title } - end - end + it 'renders for a group milestone' do + get :show, params: { group_id: group.to_param, id: group_milestone.iid } - context 'when there is not a title parameter' do - it 'searches for a group milestone' do - expect(GlobalMilestone).not_to receive(:build) - expect(Milestone).to receive(:find_by_iid) - - get :show, params: { group_id: group.to_param, id: group_milestone.id } - end + expect(response).to have_gitlab_http_status(:ok) + expect(response.body).to include(group_milestone.title) end end - it_behaves_like 'milestone tabs' - describe "#create" do it "creates group milestone with Chinese title" do post :create, @@ -277,34 +256,6 @@ expect(response).to redirect_to(group_milestone_path(group, milestone.iid)) expect(milestone.title).to eq("title changed") end - - context "legacy group milestones" do - let!(:milestone1) { create(:milestone, project: project, title: 'legacy milestone', description: "old description") } - let!(:milestone2) { create(:milestone, project: project2, title: 'legacy milestone', description: "old description") } - - it "updates only group milestones state" do - milestone_params[:title] = "title changed" - milestone_params[:description] = "description changed" - milestone_params[:state_event] = "close" - - put :update, - params: { - id: milestone1.title.to_slug.to_s, - group_id: group.to_param, - milestone: milestone_params, - title: milestone1.title - } - - expect(response).to redirect_to(group_milestone_path(group, milestone1.safe_title, title: milestone1.title)) - - [milestone1, milestone2].each do |milestone| - milestone.reload - expect(milestone.title).to eq("legacy milestone") - expect(milestone.description).to eq("old description") - expect(milestone.state).to eq("closed") - end - end - end end describe "#destroy" do diff --git a/spec/features/dashboard/milestone_tabs_spec.rb b/spec/features/dashboard/milestone_tabs_spec.rb deleted file mode 100644 index a83e4c1f7c9cfdeeab8056409696ae49cf304f54..0000000000000000000000000000000000000000 --- a/spec/features/dashboard/milestone_tabs_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe 'Dashboard milestone tabs', :js do - let(:user) { create(:user) } - let(:project) { create(:project) } - let!(:label) { create(:label, project: project) } - let(:project_milestone) { create(:milestone, project: project) } - let(:milestone) do - DashboardMilestone.build( - [project], - project_milestone.title - ) - end - let!(:merge_request) { create(:labeled_merge_request, source_project: project, target_project: project, milestone: project_milestone, labels: [label]) } - - before do - project.add_maintainer(user) - sign_in(user) - - visit dashboard_milestone_path(milestone.safe_title, title: milestone.title) - end - - it 'loads merge requests async' do - click_link 'Merge Requests' - - expect(page).to have_selector('.milestone-merge_requests-list') - end - - it 'loads participants async' do - click_link 'Participants' - - expect(page).to have_selector('#tab-participants .bordered-list') - end - - it 'loads labels async' do - click_link 'Labels' - - expect(page).to have_selector('#tab-labels .bordered-list') - end -end diff --git a/spec/features/groups/milestone_spec.rb b/spec/features/groups/milestone_spec.rb index 65ef0af5be3e690bcda10ffc611bd3f78fa9ddcf..b5790c403557d947c0a1539af16cd65d2d7cfcc4 100644 --- a/spec/features/groups/milestone_spec.rb +++ b/spec/features/groups/milestone_spec.rb @@ -102,11 +102,9 @@ expect(find('.top-area .all .badge').text).to eq("6") end - it 'lists legacy group milestones and group milestones' do - legacy_milestone = GroupMilestone.build_collection(group, group.projects, { state: 'active' }).first - + it 'lists group and project milestones' do expect(page).to have_selector("#milestone_#{active_group_milestone.id}", count: 1) - expect(page).to have_selector("#milestone_#{legacy_milestone.milestone.id}", count: 1) + expect(page).to have_selector("#milestone_#{active_project_milestone2.id}", count: 1) end it 'shows milestone detail and supports its edit' do @@ -125,75 +123,35 @@ expect(page).to have_content('v1.0') expect(page).to have_content('v1.1') expect(page).to have_content('GL-113') + expect(page).to have_link( + 'v1.0', + href: project_milestone_path(project, active_project_milestone1) + ) expect(page).to have_link( '1 Issue', - href: issues_group_path(group, milestone_title: 'v1.0') + href: project_issues_path(project, milestone_title: 'v1.0') ) expect(page).to have_link( '0 Merge Requests', - href: merge_requests_group_path(group, milestone_title: 'v1.0') + href: project_merge_requests_path(project, milestone_title: 'v1.0') + ) + expect(page).to have_link( + 'GL-113', + href: group_milestone_path(group, active_group_milestone) + ) + expect(page).to have_link( + '0 Issues', + href: issues_group_path(group, milestone_title: 'GL-113') + ) + expect(page).to have_link( + '0 Merge Requests', + href: merge_requests_group_path(group, milestone_title: 'GL-113') ) - end - - it 'renders group milestone details' do - click_link 'v1.0' - - expect(page).to have_content('expires on Aug 20, 2114') - expect(page).to have_content('v1.0') - expect(page).to have_content('Issues 1 Open: 1 Closed: 0') - expect(page).to have_link(issue.title, href: project_issue_path(issue.project, issue)) end end end describe 'milestone tabs', :js do - context 'for a legacy group milestone' do - let_it_be(:milestone) { create(:milestone, project: project) } - let_it_be(:label) { create(:label, project: project) } - let_it_be(:issue) { create(:labeled_issue, project: project, milestone: milestone, labels: [label], assignees: [create(:user)]) } - let_it_be(:mr) { create(:merge_request, source_project: project, milestone: milestone) } - - before do - visit group_milestone_path(group, milestone.title, title: milestone.title) - end - - it 'renders the issues tab' do - within('#tab-issues') do - expect(page).to have_content issue.title - end - end - - it 'renders the merge requests tab' do - within('.js-milestone-tabs') do - click_link('Merge Requests') - end - - within('#tab-merge-requests') do - expect(page).to have_content mr.title - end - end - - it 'renders the participants tab' do - within('.js-milestone-tabs') do - click_link('Participants') - end - - within('#tab-participants') do - expect(page).to have_content issue.assignees.first.name - end - end - - it 'renders the labels tab' do - within('.js-milestone-tabs') do - click_link('Labels') - end - - within('#tab-labels') do - expect(page).to have_content label.title - end - end - end - context 'for a group milestone' do let_it_be(:other_project) { create(:project_empty_repo, group: group) } let_it_be(:milestone) { create(:milestone, group: group) } diff --git a/spec/features/groups/milestones_sorting_spec.rb b/spec/features/groups/milestones_sorting_spec.rb index d27511be0b0cc6a99ce65bd0455a7e6f0f57887b..9ebb04e6f97861de5351b9a4aca678e23270f942 100644 --- a/spec/features/groups/milestones_sorting_spec.rb +++ b/spec/features/groups/milestones_sorting_spec.rb @@ -24,21 +24,12 @@ # assert default sorting within '.milestones' do - expect(page.all('ul.content-list > li').first.text).to include('v2.0') - expect(page.all('ul.content-list > li')[1].text).to include('v3.0') - expect(page.all('ul.content-list > li').last.text).to include('v1.0') + expect(page.all('ul.content-list > li strong > a').map(&:text)).to eq(['v2.0', 'v2.0', 'v3.0', 'v1.0', 'v1.0']) end click_button 'Due soon' - sort_options = find('ul.dropdown-menu-sort li').all('a').collect(&:text) - - expect(sort_options[0]).to eq('Due soon') - expect(sort_options[1]).to eq('Due later') - expect(sort_options[2]).to eq('Start soon') - expect(sort_options[3]).to eq('Start later') - expect(sort_options[4]).to eq('Name, ascending') - expect(sort_options[5]).to eq('Name, descending') + expect(find('ul.dropdown-menu-sort li').all('a').map(&:text)).to eq(['Due soon', 'Due later', 'Start soon', 'Start later', 'Name, ascending', 'Name, descending']) click_link 'Due later' @@ -46,9 +37,7 @@ # assert descending sorting within '.milestones' do - expect(page.all('ul.content-list > li').first.text).to include('v1.0') - expect(page.all('ul.content-list > li')[1].text).to include('v3.0') - expect(page.all('ul.content-list > li').last.text).to include('v2.0') + expect(page.all('ul.content-list > li strong > a').map(&:text)).to eq(['v1.0', 'v1.0', 'v3.0', 'v2.0', 'v2.0']) end end end diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb index bfff33f39566743fea83221aa3002e42390ff730..6956a7e18f6c1acfe8c74a76e5877f99731440a9 100644 --- a/spec/features/milestone_spec.rb +++ b/spec/features/milestone_spec.rb @@ -111,20 +111,6 @@ end end - describe 'deprecation popover', :js do - it 'opens deprecation popover' do - milestone = create(:milestone, project: project) - - visit group_milestone_path(group, milestone, title: milestone.title) - - expect(page).to have_selector('.milestone-deprecation-message') - - find('.milestone-deprecation-message .js-popover-link').click - - expect(page).to have_selector('.popover') - end - end - describe 'reopen closed milestones' do before do create(:milestone, :closed, project: project) diff --git a/spec/lib/milestone_array_spec.rb b/spec/lib/milestone_array_spec.rb deleted file mode 100644 index 375cb87dde63ee1ddb8cdfb3c36a201a1812406f..0000000000000000000000000000000000000000 --- a/spec/lib/milestone_array_spec.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe MilestoneArray do - let(:object1) { instance_double("BirdMilestone", due_date: Time.now, start_date: Time.now - 15.days, title: 'v2.0') } - let(:object2) { instance_double("CatMilestone", due_date: Time.now - 1.day, start_date: nil, title: 'v1.0') } - let(:object3) { instance_double("DogMilestone", due_date: nil, start_date: Time.now - 30.days, title: 'v3.0') } - let(:array) { [object1, object3, object2] } - - describe '#sort' do - it 'reorders array with due date in ascending order with nulls last' do - expect(described_class.sort(array, 'due_date_asc')).to eq([object2, object1, object3]) - end - - it 'reorders array with due date in desc order with nulls last' do - expect(described_class.sort(array, 'due_date_desc')).to eq([object1, object2, object3]) - end - - it 'reorders array with start date in ascending order with nulls last' do - expect(described_class.sort(array, 'start_date_asc')).to eq([object3, object1, object2]) - end - - it 'reorders array with start date in descending order with nulls last' do - expect(described_class.sort(array, 'start_date_desc')).to eq([object1, object3, object2]) - end - - it 'reorders array with title in ascending order' do - expect(described_class.sort(array, 'name_asc')).to eq([object2, object1, object3]) - end - - it 'reorders array with title in descending order' do - expect(described_class.sort(array, 'name_desc')).to eq([object3, object1, object2]) - end - end -end diff --git a/spec/models/global_milestone_spec.rb b/spec/models/global_milestone_spec.rb deleted file mode 100644 index 34dbdfec60d6580a4592e377e5b0774478b6ce6d..0000000000000000000000000000000000000000 --- a/spec/models/global_milestone_spec.rb +++ /dev/null @@ -1,208 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe GlobalMilestone do - let(:user) { create(:user) } - let(:user2) { create(:user) } - let(:group) { create(:group) } - let(:project1) { create(:project, group: group) } - let(:project2) { create(:project, path: 'gitlab-ci', group: group) } - let(:project3) { create(:project, path: 'cookbook-gitlab', group: group) } - - describe '.build_collection' do - let(:milestone1_due_date) { 2.weeks.from_now.to_date } - - let!(:milestone1_project1) do - create( - :milestone, - title: "Milestone v1.2", - project: project1, - due_date: milestone1_due_date - ) - end - - let!(:milestone1_project2) do - create( - :milestone, - title: "Milestone v1.2", - project: project2, - due_date: milestone1_due_date - ) - end - - let!(:milestone1_project3) do - create( - :milestone, - title: "Milestone v1.2", - project: project3, - due_date: milestone1_due_date - ) - end - - let!(:milestone2_project1) do - create( - :milestone, - title: "VD-123", - project: project1, - due_date: nil - ) - end - - let!(:milestone2_project2) do - create( - :milestone, - title: "VD-123", - project: project2, - due_date: nil - ) - end - - let!(:milestone2_project3) do - create( - :milestone, - title: "VD-123", - project: project3, - due_date: nil - ) - end - - let!(:projects) do - [ - project1, - project2, - project3 - ] - end - - let!(:global_milestones) { described_class.build_collection(projects, {}) } - - context 'when building a collection of milestones' do - it 'has all project milestones' do - expect(global_milestones.count).to eq(6) - end - - it 'has all project milestones titles' do - expect(global_milestones.map(&:title)).to match_array(['Milestone v1.2', 'Milestone v1.2', 'Milestone v1.2', 'VD-123', 'VD-123', 'VD-123']) - end - - it 'has all project milestones' do - expect(global_milestones.size).to eq(6) - end - - it 'sorts collection by due date' do - expect(global_milestones.map(&:due_date)).to eq [milestone1_due_date, milestone1_due_date, milestone1_due_date, nil, nil, nil] - end - - it 'filters milestones by search_title when params[:search_title] is present' do - global_milestones = described_class.build_collection(projects, { search_title: 'v1.2' }) - - expect(global_milestones.map(&:title)).to match_array(['Milestone v1.2', 'Milestone v1.2', 'Milestone v1.2']) - end - end - - context 'when adding new milestones' do - it 'does not add more queries' do - control_count = ActiveRecord::QueryRecorder.new do - described_class.build_collection(projects, {}) - end.count - - create_list(:milestone, 3, project: project3) - - expect do - described_class.build_collection(projects, {}) - end.not_to exceed_all_query_limit(control_count) - end - 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) - create(:closed_milestone, title: 'Closed Group Milestone 4', group: group) - end - - it 'returns the quantity of global milestones and group milestones in each possible state' do - expected_count = { opened: 2, closed: 5, all: 7 } - - count = described_class.states_count(Project.all, group) - - expect(count).to eq(expected_count) - end - - it 'returns the quantity of global milestones in each possible state' do - expected_count = { opened: 2, closed: 4, all: 6 } - - count = described_class.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 = described_class.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) } - - subject(:global_milestone) { described_class.new(milestone1_project1) } - - it 'has exactly one group milestone' do - expect(global_milestone.title).to eq('Milestone v1.2') - end - - it 'has all project milestones with the same title' do - expect(global_milestone.milestone).to eq(milestone1_project1) - end - end - - describe '#safe_title' do - let(:milestone) { create(:milestone, title: "git / test", project: project1) } - - it 'strips out slashes and spaces' do - global_milestone = described_class.new(milestone) - - 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' - - global_milestone = described_class.new(create(:active_milestone, title: title)) - - expect(global_milestone.state).to eq('active') - end - end - - context 'when all milestones are closed' do - it 'returns closed' do - title = 'Closed Group Milestone' - - global_milestone = described_class.new(create(:closed_milestone, title: title)) - - expect(global_milestone.state).to eq('closed') - end - end - end -end diff --git a/spec/models/group_milestone_spec.rb b/spec/models/group_milestone_spec.rb deleted file mode 100644 index 01856870fe046a8de315e19399c794157e53fc7c..0000000000000000000000000000000000000000 --- a/spec/models/group_milestone_spec.rb +++ /dev/null @@ -1,57 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe GroupMilestone do - let(:group) { create(:group) } - let(:project) { create(:project, group: group) } - let(:project_milestone) do - create(:milestone, title: "Milestone v1.2", project: project) - end - - describe '.build' do - it 'returns milestone with group assigned' do - milestone = described_class.build( - group, - [project], - project_milestone.title - ) - - expect(milestone.group).to eq group - end - end - - describe '.build_collection' do - let(:group) { create(:group) } - let(:project1) { create(:project, group: group) } - let(:project2) { create(:project, path: 'gitlab-ci', group: group) } - let(:project3) { create(:project, path: 'cookbook-gitlab', group: group) } - - let!(:projects) do - [ - project1, - project2, - project3 - ] - end - - it 'returns array of milestones, each with group assigned' do - milestones = described_class.build_collection(group, [project], {}) - expect(milestones).to all(have_attributes(group: group)) - end - - context 'when adding new milestones' do - it 'does not add more queries' do - control_count = ActiveRecord::QueryRecorder.new do - described_class.build_collection(group, projects, {}) - end.count - - create(:milestone, title: 'This title', project: project1) - - expect do - described_class.build_collection(group, projects, {}) - end.not_to exceed_all_query_limit(control_count) - end - end - end -end diff --git a/spec/support/shared_examples/controllers/milestone_tabs_shared_examples.rb b/spec/support/shared_examples/controllers/milestone_tabs_shared_examples.rb index d9656824452b13453e0619ec4cd6b2c7d4a8b31d..925c45005f07ffc6060000a0ffca78790694a820 100644 --- a/spec/support/shared_examples/controllers/milestone_tabs_shared_examples.rb +++ b/spec/support/shared_examples/controllers/milestone_tabs_shared_examples.rb @@ -2,15 +2,7 @@ RSpec.shared_examples 'milestone tabs' do def go(path, extra_params = {}) - params = - case milestone - when DashboardMilestone - { id: milestone.safe_title, title: milestone.title } - when GroupMilestone - { group_id: group.to_param, id: milestone.safe_title, title: milestone.title } - else - { namespace_id: project.namespace.to_param, project_id: project, id: milestone.iid } - end + params = { namespace_id: project.namespace.to_param, project_id: project, id: milestone.iid } get path, params: params.merge(extra_params) end diff --git a/spec/views/shared/milestones/_top.html.haml_spec.rb b/spec/views/shared/milestones/_top.html.haml_spec.rb index 1e209ad6f3ff0f61cd3b7474372ad8b63f893f5a..2d72e27870644928ba5d637040ce1fd8a2604ec7 100644 --- a/spec/views/shared/milestones/_top.html.haml_spec.rb +++ b/spec/views/shared/milestones/_top.html.haml_spec.rb @@ -12,22 +12,6 @@ allow(milestone).to receive(:milestone) { milestone } end - it 'renders a deprecation message for a legacy milestone' do - allow(milestone).to receive(:legacy_group_milestone?) { true } - - render 'shared/milestones/top', milestone: milestone - - expect(rendered).to have_css('.milestone-deprecation-message') - end - - it 'renders a deprecation message for a dashboard milestone' do - allow(milestone).to receive(:dashboard_milestone?) { true } - - render 'shared/milestones/top', milestone: milestone - - expect(rendered).to have_css('.milestone-deprecation-message') - end - it 'does not render a deprecation message for a non-legacy and non-dashboard milestone' do assign :group, group